Reputation: 15327
Consider the following interface declaration:
interface Foo {
bar(keys: string[], handler: (parameter: any) => void): void;
}
How can I represent that parameter
of the handler is an object with members whose keys are in the keys
array?
var x: Foo;
x.bar(['First', 'Second'], x => {
console.log(x.First);
console.log(x.Second);
});
Upvotes: 0
Views: 47
Reputation: 23443
You want
(1) can be done with a type parameter (i.e. a generic) constrained to string
, and (2) can be done with a mapped type - and it just so happens that TypeScript ships a mapped type called Record<K, T>
with it:
interface Foo {
bar<K extends string>(keys: K[], handler: (parameter: Record<K, any>) => void): void;
}
var x: Foo;
x.bar(['First', 'Second'], x => {
console.log(x.First);
console.log(x.);
});
Keep in mind, however, that if someone passes in an empty array or something other than a string literal (e.g. a variable of type string
), then you'll get no type safety. You'll be able to access any property on x
.
You can get around the empty array case by adding a generic default of never
to say "infer the empty union instead of string
when given an empty array":
interface Foo {
bar<K extends string = never>(keys: K[], handler: (parameter: Record<K, any>) => void): void;
}
Upvotes: 1
Reputation: 40584
You can use mapped types to map each of the item in the array as key:
interface Foo {
bar<T extends string>(keys: T[], handler: (parameter: {
[P in T]: any
}) => void): void;
}
var x: Foo;
x.bar(['First', 'Second'], x => {
console.log(x.First);
console.log(x.Second);
console.log(x.Third); //error
});
Upvotes: 0