- Advanced TypeScript Types Cheat Sheet (with Examples) π΅
- Ibrahima Ndaw
TypeScript is a typed language that allows you to specify variable types, function parameters, returned values, and object properties.
You can think of this article as a TypeScript advanced type cheat sheet with examples
Let’s get started!
- Intersection Types
- Union Types
- Generic Types
- Generic function
- A generic interface
- A multiparameter generic type
- Utility Types
- Partial
- Required
- Readonly
- Pick
- Omit
- Extract
- Exclude
- Record
- NonNullable
- Mapped Types
- Type Guards(Type Protection)
- typeof
- instanceof
- in
- Conditional Types
Intersection Types
Cross typing is a way to combine multiple types into one type. This means that you can merge A given type A with type B or more and get A single type with all the attributes.
type LeftType = {
id: number;
left: string;
};
type RightType = {
id: number;
right: string;
};
type IntersectionType = LeftType & RightType;
function showType(args: IntersectionType) {
console.log(args);
}
showType({ id: 1.left: 'test'.right: 'test' });
// Output: {id: 1, left: "test", right: "test"}
Copy the code
As you can see, IntersectionType combines two types — LeftType and RightType, and uses ampersand to form a cross type.
Union Types
Union types allow you to assign different types to the same variable
type UnionType = string | number;
function showType(arg: UnionType) {
console.log(arg);
}
showType('test');
// Output: test
showType(7);
// Output: 7
Copy the code
The showType function is a union type function that takes a string or a number as an argument.
Generic Types
Generic types are a way of reusing parts of a given type. It helps to capture the type T passed as a parameter.
Advantages: Create reusable functions that can support multiple types of data. This allows developers to use functions based on their own data types
Generic function
function showType<T> (args: T) {
console.log(args);
}
showType('test');
// Output: "test"
showType(1);
// Output: 1
Copy the code
How to create a generic type: You need to use <> and pass T(name is customizable) as an argument. In the π° chestnut above, we add the type variable T to showType. T helps us capture the type of the argument passed by the user (for example: number/string) and we can use this type
We call the showType function a generic function because it can be applied to multiple types
A generic interface
interface GenericType<T> {
id: number;
name: T;
}
function showType(args: GenericType<string>) {
console.log(args);
}
showType({ id: 1.name: 'test' });
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<number>) {
console.log(args);
}
showTypeTwo({ id: 1.name: 4 });
// Output: {id: 1, name: 4}
Copy the code
In the chestnut above, we declare a GenericType interface that accepts the GenericType T and constrains the type of name within the interface by type T
Note: When a generic variable constrains the entire interface, it must specify a type when implemented
So we can set name to any type of value when we use it, string or number in our example
A multiparameter generic type
interface GenericType<T, U> {
id: T;
name: U;
}
function showType(args: GenericType<number.string>) {
console.log(args);
}
showType({ id: 1.name: 'test' });
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<string.string[] >) {
console.log(args);
}
showTypeTwo({ id: '001'.name: ['This'.'is'.'a'.'Test']});// Output: {id: "001", name: Array["This", "is", "a", "Test"]}
Copy the code
A generic type can accept multiple parameters. In the above code, we pass in two parameters, T and U, and use them as types of ID,name. That is, we can now use the interface and provide different types as parameters.
Utility Types
TypeScript also provides a number of handy tools that make it easier to manipulate types. To use them, you need to pass the type to <>
Partial
Partial<T>
Partial allows you to make all properties of type T optional. It will add a? After each field. .
interface PartialType {
id: number;
firstName: string;
lastName: string;
}
/* Equivalent to interface PartialType {id? : number firstName? : string lastName? : string } */
function showType(args: Partial<PartialType>) {
console.log(args);
}
showType({ id: 1 });
// Output: {id: 1}
showType({ firstName: 'John'.lastName: 'Doe' });
// Output: {firstName: "John", lastName: "Doe"}
Copy the code
The above code declares a PartialType interface that is used as the type of the argument to the function showType(). To make all fields optional, we use the Partial keyword and pass the PartialType type as a parameter.
Required
Required<T>
Make all attributes of a type mandatory
interface RequiredType {
id: number; firstName? :string; lastName? :string;
}
function showType(args: Required<RequiredType>) {
console.log(args);
}
showType({ id: 1.firstName: 'John'.lastName: 'Doe' });
// Output: { id: 1, firstName: "John", lastName: "Doe" }
showType({ id: 1 });
// Error: Type '{ id: number: }' is missing the following properties from type 'Required<RequiredType>': firstName, lastName
Copy the code
In the code above, the addition of Required makes all attributes mandatory, even though we made some attributes optional before using the interface. TypeScript will report an error if you omit certain mandatory parameters.
Readonly
Readonly<T>
All attributes of the type are converted so that they cannot be modified
interface ReadonlyType {
id: number;
name: string;
}
function showType(args: Readonly<ReadonlyType>) {
args.id = 4;
console.log(args);
}
showType({ id: 1.name: 'Doe' });
// Error: Cannot assign to 'id' because it is a read-only property.
Copy the code
We use Readonly to make the ReadonlyType attribute unmodifiable. That is, if you try to assign a new value to one of these fields, an error will be raised.
In addition, you can use the keyword readonly in front of the specified property to make it unreassigned
interface ReadonlyType {
readonly id: number;
name: string;
}
Copy the code
Pick
Pick<T, K>
This method allows you to create a new type by selecting properties as K from an existing type T
That is, some subset of a type/interface is extracted as a new type
T represents the object K to be extracted with one constraint: it must be the combined type from all property literals of T. The new type/property must be selected from K,
From T, pick a set of properties whose keys are in the union K */
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Copy the code
interface PickType {
id: number;
firstName: string;
lastName: string;
}
function showType(args: Pick<PickType, 'firstName' | 'lastName'>) {
console.log(args);
}
showType({ firstName: 'John'.lastName: 'Doe' });
// Output: {firstName: "John"}
showType({ id: 3 });
// Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick<PickType, "firstName" | "lastName">'
Copy the code
Pick is a little different from the tools we discussed earlier in that it takes two arguments
T
Is the type of element to select fromK
Is the property to select (you can select multiple fields using union types)
Omit
Omit<T, K>
Omit Omit is the opposite of the Pick type. Instead of selecting elements, you remove K attributes from type T.
interface PickType {
id: number;
firstName: string;
lastName: string;
}
function showType(args: Omit<PickType, 'firstName' | 'lastName'>) {
console.log(args);
}
showType({ id: 7 });
// Output: {id: 7}
showType({ firstName: 'John' });
// Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick<PickType, "id">'
Copy the code
Extract
Extract<T, U>
Extract the types in T that can be assigned to U — take the intersection
Extract allows you to construct new types by selecting common properties from two different types. That is, extract from T all the attributes that can be assigned to U.
interface FirstType {
id: number;
firstName: string;
lastName: string;
}
interface SecondType {
id: number;
address: string;
city: string;
}
type ExtractType = Extract<keyof FirstType, keyof SecondType>;
// Output: "id"
Copy the code
In the above code, both the FirstType and SecondType interfaces have the ID: Number attribute. Therefore, by using Extract, a new type {id:number} is extracted.
Exclude
Exclude
,>
— Exclude from T any type that can be assigned to U.
Unlike Extract, Exclude constructs a new type by excluding common attributes that already exist in two different types. It excludes all fields from T that can be assigned to U.
interface FirstType {
id: number;
firstName: string;
lastName: string;
}
interface SecondType {
id: number;
address: string;
city: string;
}
type ExcludeType = Exclude<keyof FirstType, keyof SecondType>;
// Output; "firstName" | "lastName"
Copy the code
As you can see from the code above, the attributes firstName and lastName do not exist in the SecondType. By using the Extract keyword, we can obtain fields that are present in T but not in U.
Record
Record<K,T>
This tool helps you construct a type with a set of attributes K of a given type T. Record is handy when mapping properties of one type to properties of another type.
interface EmployeeType {
id: number;
fullname: string;
role: string;
}
let employees: Record<number, EmployeeType> = {
0: { id: 1.fullname: 'John Doe'.role: 'Designer' },
1: { id: 2.fullname: 'Ibrahima Fall'.role: 'Developer' },
2: { id: 3.fullname: 'Sara Duckson'.role: 'Developer'}};// 0: { id: 1, fullname: "John Doe", role: "Designer" },
// 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
// 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }
Copy the code
The way Record works is relatively simple. In the code, it expects a number as the type, which is why we use 0, 1, and 2 as the keys for the employees variable. If you try to use a string as an attribute, you will raise an error because the attribute is an object with the ID, fullName, and Role fields given by EmployeeType.
NonNullable
NonNullable<T>
— Remove null and undefined from T
type NonNullableType = string | number | null | undefined;
function showType(args: NonNullable<NonNullableType>) {
console.log(args);
}
showType('test');
// Output: "test"
showType(1);
// Output: 1
showType(null);
// Error: Argument of type 'null' is not assignable to parameter of type 'string | number'.
showType(undefined);
// Error: Argument of type 'undefined' is not assignable to parameter of type 'string | number'.
Copy the code
We pass the type NonNullableType as an argument to NonNullable, which constructs the new type by excluding null and undefined. That is, if you pass nullable values, TypeScript raises an error.
Incidentally, TypeScript applies non-null rules if you add the –strictNullChecks flag to the tsconfig file.
Mapped Types
Mapping types allow you to generate a new type from an old type.
Note that some of the advanced types described earlier are also mapping types. Such as:
/* Readonly, Partial and Pick are homomorphic, but Record is not. Because Record does not require an input type to copy attributes, it is not a homomorphism: */
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P inkeyof T]? : T[P]; };type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Record;
Copy the code
type StringMap<T> = {
[P in keyof T]: string;
};
function showType(arg: StringMap<{ id: number; name: string} >) {
console.log(arg);
}
showType({ id: 1.name: 'Test' });
// Error: Type 'number' is not assignable to type 'string'.
showType({ id: 'testId'.name: 'This is a Test' });
// Output: {id: "testId", name: "This is a Test"}
Copy the code
StringMap<> converts any type passed in to a string. That is, if we use it in the showType() function, the argument we receive must be a string – otherwise, TypeScript raises an error.
Type Guards(Type Protection)
Type protection allows you to check the type of a variable or object using operators. This is a conditional block that uses typeof, Instanceof, or IN return types.
Typescript can guarantee that variables are of certain types in certain blocks. Properties of this type can be carefully referenced in this block, or methods of this type can be called
typeof
function showType(x: number | string) {
if (typeof x === 'number') {
return `The result is ${x + x}`;
}
throw new Error(`This operation can't be done on a The ${typeof x}`);
}
showType("I'm not a number");
// Error: This operation can't be done on a string
showType(7);
// Output: The result is 14
Copy the code
Code that has an ordinary JavaScript conditional block that checks the typeof the received parameter through typeof.
instanceof
class Foo {
bar() {
return 'Hello World'; }}class Bar {
baz = '123';
}
function showType(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.bar());
return arg.bar();
}
throw new Error('The type is not supported');
}
showType(new Foo());
// Output: Hello World
showType(new Bar());
// Error: The type is not supported
Copy the code
Like the previous example, this is a type protection that checks if the received argument is part of the Foo class and processes it.
in
interface FirstType {
x: number;
}
interface SecondType {
y: string;
}
function showType(arg: FirstType | SecondType) {
if ('x' in arg) {
console.log(`The property ${arg.x} exists`);
return `The property ${arg.x} exists`;
}
throw new Error('This type is not expected');
}
showType({ x: 7 });
// Output: The property 7 exists
showType({ y: 'ccc' });
// Error: This type is not expected
Copy the code
Use in to check for the presence of attribute X on the parameter object.
Conditional Types
The condition type tests both types, and then selects one based on the results of that test.
A type determined by a conditional expression of the form T extends U? X: Y, that is, if type T can be assigned to type U, the resulting type is type X, otherwise it is type Y.
Conditional types make types non-unique and add flexibility to the language,
// Source code implementation
type NonNullable<T> = T extends null | undefined ? never : T;
// NotNull
equivalent to NoneNullable
,u>
// Example usage
type resType = NonNullable<string | number | null | undefined>; // string|number
Copy the code
In the above code, NonNullable checks if the type is NULL and processes based on that type. As you can see, it uses JavaScript ternary operators.
Thanks for reading.