Some useful parts
// general
const list1: number[] = [1, 2, 3];
// use Generic
const list2: Array<number> = [1, 2, 3];
# PRESENTING CODE
function returnNumber(arg: number): number {
return arg;
}
function returnString(arg: string): string {
return arg;
}
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString"); // output: string
let output = identity("myString"); // output: string by type argument inference
# PRESENTING CODE
// How to assign type for getLength
function getLength(arg) { // Parameter 'arg' implicitly has an 'any' type,
return arg.length;
}
function getLength<T>(arg: T): number {
return arg.length; // error: Property 'length' does not exist on type 'T'.
}
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg: T): number {
return arg.length;
}
getLength(3); // error: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.
getLength('abc'); // ✅
getLength([]); // ✅
getLength({ length: 1, value: 3 }); // ✅
# PRESENTING CODE
type Address = {
street: string;
city: string;
country: string;
};
const keyAbc: keyof Address = 'a'; // error: Type '"a"' is not assignable to type 'keyof Address'.
// keyof Address is "street" | "city" | "country"
const keyCity: keyof Address = 'city'; // ✅
# PRESENTING CODE
function prop(obj, key) {
return obj[key];
}
prop({ city: 'Taipei', country: 'Taiwan' }, 'city'); // return "Taipei"
prop({ city: 'Taipei', country: 'Taiwan' }, 'csity'); // no any hint for Developer typo
function prop<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
prop({ city: 'Taipei', country: 'Taiwan' }, 'city'); // return "Taipei"
prop({ city: 'Taipei', country: 'Taiwan' }, 'csity');
// error: Argument of type '"csity"' is not assignable to parameter of type '"city" | "country"'.
# PRESENTING CODE
type UserEmailInput = string | null | undefined;
// type UserEmail = string
type UserEmail = NonNullable<UserEmailInput>;
# PRESENTING CODE
# PRESENTING CODE
extends
(T) is assignable to the one on the right (U) or not?type Foo = null extends null | undefined ? string : number;
// type Foo is string
type Bar<Type> = Type extends null | undefined ? string : number;
type Qoo1 = Bar<null>; // string
type Qoo2 = Bar<boolean>; // number
type Qoo3 = Bar<any>; // ?
# PRESENTING CODE
type UserEmailInput = string | null | undefined;
type NonNullable<T> = T extends null | undefined ? never : T;
type UserEmail = NonNullable<UserEmailInput>;
// equal to expand type alias UserEmailInput
type UserEmail = NonNullable<string | null | undefined>;
// equal to expand type unions
type UserEmail =
| NonNullable<string>
| NonNullable<null>
| NonNullable<undefined>;
// equal to expand type alias NonNullable
type UserEmail =
| (string extends null | undefined ? never : string)
| (null extends null | undefined ? never : null)
| (undefined extends null | undefined ? never : undefined);
// equal to
type UserEmail = string | never | never ;
// equal to (never is a subtype of all types, so we can omit it here)
type UserEmail = string;
# PRESENTING CODE
type Address = {
street: string;
city: string;
country: string;
};
type City = Address['city']; // City is a string type
type I1 = Address["street" | "city"];
type I2 = Address[keyof Address];
type Movies = string[];
type FavoriteMovie = Movies[number]; // FavoriteMovie is a string type
type Age = MovieStarList[number]["age"];
# PRESENTING CODE
type FeatureFlags = {
darkMode: () => void;
newUserProfile: () => void;
};
type FeatureOptions = OptionsFlags<FeatureFlags>;
// equal to
type FeatureOptions = {
darkMode: boolean;
newUserProfile: boolean;
}
# PRESENTING CODE
type FeatureFlags = {
darkMode: () => void;
newUserProfile: () => void;
};
type FeatureOptions = OptionsFlags<FeatureFlags>;
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
// equal to
type FeatureOptions = {
darkMode: boolean;
newUserProfile: boolean;
}
# PRESENTING CODE
type Concrete<Type> = {
[Property in keyof Type]-?: Type[Property];
};
type MaybeUser = {
id: string;
name?: string;
age?: number;
};
type User = Concrete<MaybeUser>;
// equal to
type User = {
id: string;
name: string;
age: number;
}
# PRESENTING CODE
# PRESENTING CODE
type Simplify<T> = T extends Record<string, any>
? {
[K in keyof T]: Simplify<T[K]>
}
: T;
# PRESENTING CODE
// reference: https://michalzalecki.com/nominal-typing-in-typescript/
type Brand<K, T> = K & { __brand: T }
type USD = Brand<number, "USD">
type EUR = Brand<number, "EUR">
const usd = 10 as USD;
const eur = 10 as EUR;
function gross(net: USD, tax: USD): USD {
return (net + tax) as USD;
}
gross(usd, usd); // ok
gross(eur, usd); // Type '"EUR"' is not assignable to type '"USD"'.
# PRESENTING CODE