Artur Czemiel
12/11/2018
Hello, This is the second article of the advanced typescript tutorial series. Today I'll cover the basic usage of
extends
keyword and conditional types. How does conditional type looks like?
type StringOrArray<T> = T extends string[] ? 'array' : T extends string ? 'string' : never
const a:string = "hello"
const b:string[] = ["hello","world"]
const c:number = 1
const d:StringOrArray<typeof a> = "string"
const e:StringOrArray<typeof b> = "array"
let f:StringOrArray<typeof c>
So let's analyze this code:
To be the truth this code is useless but can give you some scope how extends
keyword works. Next example will be a real-world example where we determine the type of the form field to give the user correct options.
type FieldType = "string" | "float" | "date"
type BaseField = {
name:string
}
type Field<T extends FieldType> = BaseField & {
value: T extends "string" ? string : T extends "float" ? number : T extends "date" ? Date : never
}
const stringField:Field<"string"> = {
name:"myfield",
value:"aaa"
}
const floatField:Field<"float"> = {
name:"myfield",
value:1.0
}
const dateField:Field<"date"> = {
name:"myfield",
value: new Date()
}
This is a little bit more advanced. What's going on with FieldType? It just checks the string converted to generic type to return correct type.
type FieldType = "string" | "float" | "date";
type BaseFieldExtended = {
name: string;
type: FieldType;
};
const FieldExtended = <T extends BaseFieldExtended>(
baseField: T & {
value: T["type"] extends "string"
? string
: T["type"] extends "date"
? Date
: T["type"] extends "float"
? number
: never;
}
) => baseField;
FieldExtended({
name: "a",
type: "string",
value: "bbb"
});
FieldExtended({
name: "a",
type: "float",
value: 12
});
FieldExtended({
name: "a",
type: "date",
value: new Date()
});
And this is what typescript is made for. To provide complicated autocompletion stuff :). Wait for the next series of advanced typescript tutorial.