'is not assignable to parameter of type' error with object literal
There is a problem with object literal type.
interface OptionalFoo {
foo?: number;
}
interface Bar {}
function foobarFn(foobar: OptionalFoo & Bar) {}
foobarFn({ bar: 1 }); // error
foobarFn({ bar: 1 } as { bar: number }); // ok
foobarFn({ bar: 1 } as { bar: 1 }); // ok!
Object literal with inferred type causes type error:
Argument of type '{ bar: number; }' is not assignable to parameter of type 'OptionalFoo & Bar'
But the problem is not the inference itself:
const bar = { bar: 1 }; // inferred { bar: number; }
foobarFn(bar); // ok!?
The same problem with spread syntax vs Object.assign:
foobarFn({...{ bar: 1 }}); // error
foobarFn(Object.assign({}, { bar: 1 })); // ok!?
Is there a way to achieve the behaviour with inferred object literal type (excess property check) without in-place object literal, e.g. with bar variable or function call like Object.assign({ bar: 1 })?
typescript type-inference
add a comment |
There is a problem with object literal type.
interface OptionalFoo {
foo?: number;
}
interface Bar {}
function foobarFn(foobar: OptionalFoo & Bar) {}
foobarFn({ bar: 1 }); // error
foobarFn({ bar: 1 } as { bar: number }); // ok
foobarFn({ bar: 1 } as { bar: 1 }); // ok!
Object literal with inferred type causes type error:
Argument of type '{ bar: number; }' is not assignable to parameter of type 'OptionalFoo & Bar'
But the problem is not the inference itself:
const bar = { bar: 1 }; // inferred { bar: number; }
foobarFn(bar); // ok!?
The same problem with spread syntax vs Object.assign:
foobarFn({...{ bar: 1 }}); // error
foobarFn(Object.assign({}, { bar: 1 })); // ok!?
Is there a way to achieve the behaviour with inferred object literal type (excess property check) without in-place object literal, e.g. with bar variable or function call like Object.assign({ bar: 1 })?
typescript type-inference
1
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04
add a comment |
There is a problem with object literal type.
interface OptionalFoo {
foo?: number;
}
interface Bar {}
function foobarFn(foobar: OptionalFoo & Bar) {}
foobarFn({ bar: 1 }); // error
foobarFn({ bar: 1 } as { bar: number }); // ok
foobarFn({ bar: 1 } as { bar: 1 }); // ok!
Object literal with inferred type causes type error:
Argument of type '{ bar: number; }' is not assignable to parameter of type 'OptionalFoo & Bar'
But the problem is not the inference itself:
const bar = { bar: 1 }; // inferred { bar: number; }
foobarFn(bar); // ok!?
The same problem with spread syntax vs Object.assign:
foobarFn({...{ bar: 1 }}); // error
foobarFn(Object.assign({}, { bar: 1 })); // ok!?
Is there a way to achieve the behaviour with inferred object literal type (excess property check) without in-place object literal, e.g. with bar variable or function call like Object.assign({ bar: 1 })?
typescript type-inference
There is a problem with object literal type.
interface OptionalFoo {
foo?: number;
}
interface Bar {}
function foobarFn(foobar: OptionalFoo & Bar) {}
foobarFn({ bar: 1 }); // error
foobarFn({ bar: 1 } as { bar: number }); // ok
foobarFn({ bar: 1 } as { bar: 1 }); // ok!
Object literal with inferred type causes type error:
Argument of type '{ bar: number; }' is not assignable to parameter of type 'OptionalFoo & Bar'
But the problem is not the inference itself:
const bar = { bar: 1 }; // inferred { bar: number; }
foobarFn(bar); // ok!?
The same problem with spread syntax vs Object.assign:
foobarFn({...{ bar: 1 }}); // error
foobarFn(Object.assign({}, { bar: 1 })); // ok!?
Is there a way to achieve the behaviour with inferred object literal type (excess property check) without in-place object literal, e.g. with bar variable or function call like Object.assign({ bar: 1 })?
typescript type-inference
typescript type-inference
edited Nov 23 '18 at 11:00
estus
asked Nov 23 '18 at 10:30
estusestus
72.4k22106224
72.4k22106224
1
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04
add a comment |
1
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04
1
1
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04
add a comment |
1 Answer
1
active
oldest
votes
Just to make things clear this is not just about excess property checks. Excess property checks come into play when we assign an object literal directly to a location. In your case all the more surprising behavior occurs when assigning an object indirectly, which would normally be allowed under excess property checks.
function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect
The surprising part, at least to me is thst another check (the weak type check) does not catch this error. Under weak type checks (as described here) if a type has only optional properties, and we try to assign a type that has no properties in common with it we should get an error:
function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties: Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.
I think this is a hole (I hesitate to say bug not sure if it is by design or not) in weak type checks. A weak type is (according to this PR):
- Object types with at least one property
- Where all properties are optional
- And that do not have a string index signature, number index signature, call signature or construct signature.
However in the implementation of the weak type check for intersections all types of the intersection have to be weak types for the intersection to be a weak type. From compiler code (comments added):
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
// ....
}
if (type.flags & TypeFlags.Intersection) {
/// All intersection members have to be weak
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
Since interface Bar {} is not a weak type (as per the first rule, it has no properties) any intersection with it will not be a weak type and will not throw any weak type checking errors. Removing Bar from the intersection will throw errors everywhere you assign an object that has nothing in common with the target .
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,foobarFn({...bar}).
– estus
Nov 23 '18 at 11:21
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444963%2fis-not-assignable-to-parameter-of-type-error-with-object-literal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Just to make things clear this is not just about excess property checks. Excess property checks come into play when we assign an object literal directly to a location. In your case all the more surprising behavior occurs when assigning an object indirectly, which would normally be allowed under excess property checks.
function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect
The surprising part, at least to me is thst another check (the weak type check) does not catch this error. Under weak type checks (as described here) if a type has only optional properties, and we try to assign a type that has no properties in common with it we should get an error:
function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties: Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.
I think this is a hole (I hesitate to say bug not sure if it is by design or not) in weak type checks. A weak type is (according to this PR):
- Object types with at least one property
- Where all properties are optional
- And that do not have a string index signature, number index signature, call signature or construct signature.
However in the implementation of the weak type check for intersections all types of the intersection have to be weak types for the intersection to be a weak type. From compiler code (comments added):
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
// ....
}
if (type.flags & TypeFlags.Intersection) {
/// All intersection members have to be weak
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
Since interface Bar {} is not a weak type (as per the first rule, it has no properties) any intersection with it will not be a weak type and will not throw any weak type checking errors. Removing Bar from the intersection will throw errors everywhere you assign an object that has nothing in common with the target .
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,foobarFn({...bar}).
– estus
Nov 23 '18 at 11:21
add a comment |
Just to make things clear this is not just about excess property checks. Excess property checks come into play when we assign an object literal directly to a location. In your case all the more surprising behavior occurs when assigning an object indirectly, which would normally be allowed under excess property checks.
function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect
The surprising part, at least to me is thst another check (the weak type check) does not catch this error. Under weak type checks (as described here) if a type has only optional properties, and we try to assign a type that has no properties in common with it we should get an error:
function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties: Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.
I think this is a hole (I hesitate to say bug not sure if it is by design or not) in weak type checks. A weak type is (according to this PR):
- Object types with at least one property
- Where all properties are optional
- And that do not have a string index signature, number index signature, call signature or construct signature.
However in the implementation of the weak type check for intersections all types of the intersection have to be weak types for the intersection to be a weak type. From compiler code (comments added):
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
// ....
}
if (type.flags & TypeFlags.Intersection) {
/// All intersection members have to be weak
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
Since interface Bar {} is not a weak type (as per the first rule, it has no properties) any intersection with it will not be a weak type and will not throw any weak type checking errors. Removing Bar from the intersection will throw errors everywhere you assign an object that has nothing in common with the target .
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,foobarFn({...bar}).
– estus
Nov 23 '18 at 11:21
add a comment |
Just to make things clear this is not just about excess property checks. Excess property checks come into play when we assign an object literal directly to a location. In your case all the more surprising behavior occurs when assigning an object indirectly, which would normally be allowed under excess property checks.
function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect
The surprising part, at least to me is thst another check (the weak type check) does not catch this error. Under weak type checks (as described here) if a type has only optional properties, and we try to assign a type that has no properties in common with it we should get an error:
function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties: Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.
I think this is a hole (I hesitate to say bug not sure if it is by design or not) in weak type checks. A weak type is (according to this PR):
- Object types with at least one property
- Where all properties are optional
- And that do not have a string index signature, number index signature, call signature or construct signature.
However in the implementation of the weak type check for intersections all types of the intersection have to be weak types for the intersection to be a weak type. From compiler code (comments added):
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
// ....
}
if (type.flags & TypeFlags.Intersection) {
/// All intersection members have to be weak
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
Since interface Bar {} is not a weak type (as per the first rule, it has no properties) any intersection with it will not be a weak type and will not throw any weak type checking errors. Removing Bar from the intersection will throw errors everywhere you assign an object that has nothing in common with the target .
Just to make things clear this is not just about excess property checks. Excess property checks come into play when we assign an object literal directly to a location. In your case all the more surprising behavior occurs when assigning an object indirectly, which would normally be allowed under excess property checks.
function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect
The surprising part, at least to me is thst another check (the weak type check) does not catch this error. Under weak type checks (as described here) if a type has only optional properties, and we try to assign a type that has no properties in common with it we should get an error:
function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties: Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.
I think this is a hole (I hesitate to say bug not sure if it is by design or not) in weak type checks. A weak type is (according to this PR):
- Object types with at least one property
- Where all properties are optional
- And that do not have a string index signature, number index signature, call signature or construct signature.
However in the implementation of the weak type check for intersections all types of the intersection have to be weak types for the intersection to be a weak type. From compiler code (comments added):
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
// ....
}
if (type.flags & TypeFlags.Intersection) {
/// All intersection members have to be weak
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
Since interface Bar {} is not a weak type (as per the first rule, it has no properties) any intersection with it will not be a weak type and will not throw any weak type checking errors. Removing Bar from the intersection will throw errors everywhere you assign an object that has nothing in common with the target .
answered Nov 23 '18 at 11:13
Titian Cernicova-DragomirTitian Cernicova-Dragomir
65.3k34361
65.3k34361
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,foobarFn({...bar}).
– estus
Nov 23 '18 at 11:21
add a comment |
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,foobarFn({...bar}).
– estus
Nov 23 '18 at 11:21
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,
foobarFn({...bar}).– estus
Nov 23 '18 at 11:21
Thanks, great explanation. Also just found that the check at least can be triggered where needed with spreads,
foobarFn({...bar}).– estus
Nov 23 '18 at 11:21
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53444963%2fis-not-assignable-to-parameter-of-type-error-with-object-literal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
typescriptlang.org/docs/handbook/…
– JB Nizet
Nov 23 '18 at 10:42
@JBNizet Thanks for the reference, totally forgot about this term. Yes, that's it. I wonder if it's possible to trigger excess property check where it isn't applied by TS, like when an object is passed as a variable.
– estus
Nov 23 '18 at 11:02
@estus It's not just about that .. I think it's about weak types ...
– Titian Cernicova-Dragomir
Nov 23 '18 at 11:02
That would necessitate runtime checks, not compile-time checks.
– JB Nizet
Nov 23 '18 at 11:04