In the current version (2.1) of TypeScript I can constrain a method argument on a generic class to be a property of the generic type.
class Foo<TEntity extends {[key:string]:any}> {
public bar<K extends keyof TEntity>(key:K, value:TEntity[K]) { }
}
Is it possible in the current type system to constrain the key part even further to be a subset where the value of the key is of a certain type?
What I'm looking for is something along the lines of this psuedo code.
class Foo<TEntity extends {[key:string]:any}> {
public updateText<K extends keyof TEntity where TEntity[K] extends string>(key:K, value:any) {
this.model[key] = this.convertToText(value);
}
}
EDIT
For clarification I added a more complete example of what I'm trying to achieve.
type object = { [key: string]: any };
class Form<T extends object> {
private values: Partial<T> = {} as T;
protected convert<K extends keyof T>(key: K, input: any, converter: (value: any) => T[K])
{
this.values[key] = converter(input);
}
protected convertText<K extends keyof T>(key: K, input: any)
{
this.values[key] = this.convert(key, input, this.stringConverter);
}
private stringConverter(value: any): string
{
return String(value);
}
}
Demo on typescriptlang.org
convertText
will give an error saying that Type 'string' is not assignable to type 'T[K]'
.
Given
interface Foo {
s: string
n: number
}
The compiler can tell that this will work
this.convert('s', 123, v => String(v));
and this will not
this.convert('n', 123, v => String(v));
I'm hoping I can constrain the convertText
method to keys where the value is of type string
to get type safety on the key parameter.
keyof is a keyword in TypeScript which is used to extract the key type from an object type.
Assigning Generic ParametersBy passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.
Generics allow creating 'type variables' which can be used to create classes, functions & type aliases that don't need to explicitly define the types that they use. Generics makes it easier to write reusable code.
Using type parameters in generic constraintsTypeScript allows you to declare a type parameter constrained by another type parameter. The following prop() function accepts an object and a property name. It returns the value of the property.
It is possible (using a non-class example here). The following will ensure that T[P]
is a string.
function convertText<T extends {[key in P]: string }, P extends keyof T>(data: T, field: P & keyof T) {
// ...
}
The idea is to narrow the type of T
to only the fields inferred in P
and set the exact type you want, in this case string
.
Test:
let obj = { foo: 'lorem', bar: 2 };
convertText(obj, 'foo');
convertText(obj, 'bar'); // fails with: Type 'number' is not assignable to type 'string'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With