-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
please delete, thx #60524
Comments
setting
|
Note: not a TS team member. Duplicate of #11100, tracked at #10727.
And even if that existed it would still fail to catch problems in general without exact types as per #12936, since nothing prevents you from sneaking random extra stuff in there: const x = { template: 123 }
const y: {} = x; // okay
const base: Thing = { template: "foobar" }; // Thing
const result = Object.assign({}, base, y); // Thing?!
result.template.toUpperCase(); // runtime explosion because it's really a number So |
yep, that seems to help, sadly in my case the property will be set by the user of the library I'm trying to build (hence the name EDIT: I have now tested this further and enabling the setting does not change the behaviour of @jcalz the major issue I see with your example is the use of |
"acts virtually identical to interface Thing {
template: string;
color?: string;
}
const x = { color: "abc", template: 123 }
const y: { color: string } = x;
const base: Thing = { template: "foobar" }; // Thing
const result = Object.assign({}, base, y); // Thing & {color: string}
result.template.toUpperCase(); // runtime explosion because it's really a number Does that demonstrate the issue to you? |
This does not disprove
This exits the realm of explicilty setting |
I was hoping to avoid this discussion by changing the example. I agree that
Widening is not "lying" to TypeScript's type analysis. The following is not lying, it's just widening: interface Foo { x: string }
interface Baz extends Foo { y: string }
function f(foo: Foo): Baz { return Object.assign({}, { y: "abc" }, foo); }
interface Bar extends Foo { y: number }
const bar: Bar = { x: "abc", y: 123 };
const baz = f(bar);
baz.y.toUpperCase() // error If you want to fix that problem, you need exact types. If you think it's off-topic, let's forget about it entirely. Sorry for the digression. Optional properties accept type Arg = { [K in keyof Thing]: Thing[K] | undefined };
/* type Arg = {
template: string | undefined;
color?: string | undefined;
} */
const base: Thing = { template: "foobar" }; // Thing
const arg: Arg = { color: "red", template: undefined }; // Arg
const result = Object.assign({}, base, arg); // Thing & Arg
result.template // string Indeed we can change type Arg = { [K in keyof Thing]: Thing[K] | number };
/* type Arg = {
template: string | number;
color?: string | number;
} */
const base: Thing = { template: "foobar" }; // Thing
const arg: Arg = { color: "red", template: 123 }; // Arg
const result = Object.assign({}, base, arg); // Thing & Arg
result.template // string The problem here is the lack of a spread operator. Here's a possible spread implementation: type MergeTwo<T extends object, U extends object> = { [
K in keyof T | keyof U]:
(x: K extends (keyof T & keyof U) ?
{} extends Pick<U, K> ? { [P in keyof T as P & K]: T[P] | U[K] } : Pick<U, K> :
K extends keyof T ? Pick<T, K> : K extends keyof U ? Pick<U, K> : never) => void
} extends Record<keyof T | keyof U, (x: infer I) => void> ? { [K in keyof I]: I[K] } : never
type Merge<T extends object[], A extends object = object> =
T extends [infer F extends object, ...infer R extends object[]]
? Merge<R, object extends A ? F : MergeTwo<A, F>> : A;
interface ObjectConstructor {
assign<T extends [object, ...object[]]>(...args: T): Merge<T>
} which gives you type Arg = Partial<Thing>;
const base: Thing = { template: "foobar" }; // Thing
const arg: Arg = { color: "red", template: undefined }; // Partial<Thing>
const result = Object.assign({}, base, arg);
/* const result: {
template: string | undefined;
color?: string | undefined;
} */
result.template // string | undefined
const y = Object.assign({}, base, { template: Math.random() < 0.99 ? 123 : "abc" })
/* const y: {
template: string | number;
color?: string | undefined;
} */ But that |
can you cease writing essays about unrelated stuff in my issue please? |
It’s not unrelated. As for writing essays, that’s a fair point. I’ll disengage now entirely. Good luck. |
Your write-up is still appreciated for future reference. |
Dunno why I thought using github issues in public was a valid way to report incorrect behaviour in software.
The text was updated successfully, but these errors were encountered: