I need to define two types:
- Type for object which holds some data with values of defined types
- Type for object which holds validators for the values contained in object with the first type
My realization:
type Data = Record<string, string|number|Array<string>>
type Validators<T extends Data> = {
[P in keyof T]?: (value: T[P]) => string
}
interface MyData extends Data {
first: string,
second: number,
third: Array<string>,
}
const validators: Validators<MyData> = {
first: (value: string) => "",
};
With this realization i get the error for the validators object:
TS2322: Type '{ first: (value: string) => string; }' is not assignable to type 'Validators'.
Property 'first' is incompatible with index signature.
Type '(value: string) => string' is not assignable to type '(value: string | number | string[]) => string'.
Types of parameters 'value' and 'value' are incompatible.
Type 'string | number | string[]' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
Is it possible to define such types in typescript?
CodePudding user response:
Is it possible to define such types in typescript?
Yes. The problem is that by extending Data, MyData now has a string index that returns string | number | Array<string>:
// as if you had written this
interface MyData {
first: string,
second: number,
third: Array<string>,
[k: string]: string | number | Array<string>
}
When building the Validator, the first key matches both your first key and your string index.
Because of that, typescript expects a function that matches (value: string) => string, but also matches (value: string | number | Array<string>) => string.
Since you're providing a function that only accepts a string as a parameter, the compilation breaks.
If you want to apply the type restriction of string | number | Array<string> to the interfaces that use Validators, you should not use a string index, but a index that just uses the subtype keys:
type Data<Subtype> = Record<keyof Subtype, string | number | Array<string>>
type Validators<Subtype extends Data<Subtype>> = {
[P in keyof Subtype]?: (value: Subtype[P]) => string
}
interface MyData {
first: string
second: number
third: Array<string>
}
const validators: Validators<MyData> = {
first: (value: string) => "",
};
