Reputation: 79
I would like to ensure that type A has a field of a generic type but the name of that field is defined by the value of a field from another object.
E.g. the function:
interface IndexedContext<K extends string, T> {
context: T;
key: K;
}
type TypeB<P, K, T> = {
// this field should be named after IndexedContext[key]
P[K] = T;
}
const Consumer =
<T extends object, K>(context: IndexedContext<K, T>) => <C extends ComponentType<TypeA>, TypeA extends TypeB: C => {
.....
};
TypeA (props) should have a field which is the value of the field key in IndexedKey? So that when I use this decorator on a react component and pass a ReactContext to it I can make sure that the props have a field which is the same as the key.
@Consumer({context: MyContext, key: 'myKey'})
class MyClass extends Component<MyProps> {}
interface MyProps {
// compiler should fail if this key is missing.
myKey: // Type of value of MyContext
}
Upvotes: 2
Views: 54
Reputation: 249726
You don't need to define any extra mapped types (such as TypeB
sould be in your example), you can use Record
to get a mapped type from a string literal and a field type.
You also need to capture the instance type not the constructor. If you write {context: MyContext, key: 'myKey'}
, context
will be the class MyContext
, and so T
will be inferred to typeof MyContext
not MyContext
. To get the instance type you could type context
as new (...a:any[]) => T
.
Putting it all together:
interface IndexedContext<K extends string, T> {
context: Type<T>;
key: K;
}
type Type<T> = new (...a: any[]) => T
const Consumer =
<T extends object, K extends string>(context: IndexedContext<K, T>) => <C extends ComponentType<Record<K, T>>>(cls: C) => {
};
class MyContext { }
@Consumer({ context: MyContext, key: 'myKey' })
class MyClass extends Component<MyProps> { }
interface MyProps {
// compiler WILL fail if this key is missing.
myKey: MyContext// Type of value of MyContext
}
Note context
will have to be assigned a class for this to work, you will not be able to directly use interfaces or primitives.
Upvotes: 1