-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Union in a computed property allows any assignment to property value #38663
Comments
@weswigham what's the designed behavior here? |
So, there's two things, first: declare var str: string;
const x = { a: "", b: "" };
const y = { [str]: 0, ...x };
const z = { ...x, [str]: 0 }; A computed property name with a non-literal name produces an index signature. {
[x: string]: number;
a: string;
b: string;
} where the index signature does not actually cover all the members in the type, but that can be fixed. Second, |
+1 on this, allowed a bad type to silently survive during a refactor for us. |
Here's my minimal example, similar to OP's: type Key = 'foo' | 'bar';
// Ex 1. Attempting to assign `unknown` in place of `string`
declare const unknownValue: unknown;
const dict1: Partial<Record<Key, string>> = {
foo: unknownValue, // Error ✔️
};
// Ex 2. Attempting to assign `unknown` in place of `string`, except this time using a computed property
declare const keyValuePair: {
key: Key;
value: unknown;
};
const dict2: Partial<Record<Key, string>> = {
[keyValuePair.key]: keyValuePair.value, // No Error ❌
}; |
I think we could get away with raising an error for t = { [k]: v } when k is a literal union type "s1" | "s2" | "s3" ... and v isn't assignable to the union t["s1"] | t["s2"] | t["s3"] | ... (intersection would be more sound, but impractical due to producing never a lot of the time). It'd be a breaking change but it's hard to see how that code wouldn't have an actual bug. |
The examples in the previous posts show unexpected behavior where the value is not type-safe. I noticed a similar issue with a dynamic key, although I am not sure whether this is strictly related. My use-case is working with prisma as an ORM to dynamically update a column where a correct call looks like this: prisma.table.update({
data: {
columnToUpdate: newValue,
}
}); I wanted to dynamically select the column to update and did type T = {
one?: 1;
};
type Keys = 'one' | 'two';
const dynamicKey = (): Keys => 'two';
const absurd: T = {
[dynamicKey()]: 2 // TS silently accepts this, both key AND value
}; |
You say that, but #30769 exists. 🚎 (Lots of people did used to trip on that one, but it doesn’t seem like a big stumbling block anymore.) |
Is there any update on this? Could this at least be considered a bug? This has allowed a very preventable bug to exist in our code for ages where a string value is set in an object that may only contain numbers (minimal example below). I realise it would be a breaking change, but maybe it could at least be added behind a compiler option or something. type OnlyNumberValues = {
foo: number
bar: number
}
const whyDoesThisWork = (obj: OnlyNumberValues, key: keyof OnlyNumberValues): OnlyNumberValues => ({
...obj,
[key]: 'definitely not a number'
}) |
TypeScript Version: 4.0.0-dev.20200518
Search Terms: computed property, union
Code
Expected behavior:
Expected error for invalid assignments in
index4
andindex5
.Actual behavior:
No error, allowing anything to be assigned to string
Playground Link: here
Related Issues:
#36920: perhaps the computed property is deemed an excess property, though I don't think it should be
The text was updated successfully, but these errors were encountered: