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) => "",
};