-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Using const string enum as object key produces an indexed type #16687
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
This should also work for numeric enums. |
Is this the same error? function make<Name extends string, Value>(name: Name, value: Value): Record<Name, Value> {
return {
[name]: value,
};
} Gives:
|
@simonbuchan Not really. @Kovensky wants the keys of strings enums to be statically known for use in computed properties. You want one unknown member of an unknown set of keys to be create a type with computed name in it. Something like Unfortunately, Typescript doesn't have a type like this, though, so instead the type inferred for the object literal has a string indexer, which is not assignable to a mapped type, even though both have an unknown set of allowed properties. You'll have to read the PRs for mapped types, but I think the reason is that a string indexer will always have an unknown set of properties, but the mapped type, when instantiated, will have a particular set of properties. For example: make('hi', 'there'): Record<'hi', string> And |
@sandersn I think I get it reflecting on this a bit: function make<Name extends literal string, Value>(name: Name, value: Value): { [name: Name]: Value };
make("foo", "bar"); // { foo: string } - though I would like { foo: "bar" }, that's another issue
["foo", "bar"].map(name => make(name, name)); // either error on make "'string' is not assignable to 'literal string' or Array<{ [name: string]: string }> as before?
function zipMake<Names extends string, Values>(names: Names[], values, Values[]) {
return names.map((name, i) => make(name, values[i])); // "'Names' is not assignable to 'literal string'"
}
function zipMake<Names extends literal string, Values>(names: Names[], values, Values[]); // Either error or can only be called with 0 or 1-length literal array of `names` (or matching constrained type)? This arose when I was playing around with a toy version of type WithCounterEnhancer = <ExternalProps>(
wrappedComponent: React.ComponentType<ExternalProps & { counter: number, setCounter(value: number }>,
): React.ComponentType<ExternalProps>; I could get it to typecheck pretty well externally with |
@simonbuchan Do you mind creating a separate issue for this with your example code and discussion? This feels like it is generating discussion distinct from that based on the original example. I'll see if I can answer your questions there. |
another interesting use case described in #17784 class Component<S> {
state: S;
setState(partialState: Partial<S>) { }
onFiledChanged = (filedName: keyof S) => (value) => {
this.setState({ [filedName]: value });
}
render() {
return <form>
<input onChange={ this.onFiledChanged('foo') } />
<input onChange={ this.onFiledChanged('bar') } />
</form>
}
} |
#15473 should be to fix this. |
Note that this does not cover the generic case, i.e. function f<K extends string>(k: K) {
return { [k]: 0 } ; // type is { [x:string]: number}
} for these cases we recommend casting to type Unionize<T> = {[P in keyof T]: {[Q in P]: T[P]}}[keyof T];
function f<K extends string>(k: K) {
return { [k]: 0 } as Unionize<{[P in K]: number}>;
} |
Edit 3: OK, tried on nightlies, and it looks like with #18317 |
I would like this feature to work too, but I have a couple of issues
export const enum StepNames {
one = 'one',
two = 'two',
final = 'final'
}
export type Step = {[key in StepNames]: {header: string}}; When I try to use it like: const oneStep: Step = { 'one': { header: 'First' } }; I get this compile error:
const enum Test {
A = 'a',
B = 'b'
}
type TestMap<T> = {[key in keyof T]: string}
const x: TestMap<Test> = {
['a']: 'string',
['b']: 'another string'
}
// Error: TS2322: Type '{ ['a']: string; ['b']: string; }' is not assignable to type 'Test'. Is there any way to get around this problem? |
@SLaks Thanks. Sorry for the basic questions. |
TypeScript Version: nightly (2.5.0-dev.20170621)
Code
Expected behavior:
Keys from a string enum to be usable as static key names, similar to how constant strings are usable in computed key position. This probably should work even with non-
const
enums.Actual behavior:
Not usable without a (potentially incorrect?) type assertion.
The text was updated successfully, but these errors were encountered: