TypeScript - це набрана мова, яка дозволяє вказати тип змінних, параметри функції, повернені значення та властивості об'єкта.
Тут розширена шпаргалка TypeScript Types із прикладами.
Зануримось.
- Типи перетину
- Типи об'єднань
- Загальні типи
- Типи утиліт
- Частково
- вимагається
- Лише для читання
- Виберіть
- Опустити
- Витяжка
- Виключити
- Запис
- NonNullable
- Позначені типи
- Тип гвардії
- Умовні типи
Типи перетину
Тип перетину - це спосіб об’єднання декількох типів в один. Це означає, що ви можете об'єднати даний тип A з типом B або більше і повернути один тип із усіма властивостями.
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"}
Як ви можете бачити, IntersectionType
поєднує в собі два типи - LeftType
і RightType
та використовує &
знак , щоб побудувати тип перетину.
Типи об'єднань
Типи об’єднань дозволяють мати анотації різних типів у межах даної змінної.
type UnionType = string | number function showType(arg: UnionType) { console.log(arg) } showType("test") // Output: test showType(7) // Output: 7
Функція showType
- це тип об’єднання, який приймає як параметри як рядки, так і числа.
Загальні типи
Загальний тип - це спосіб повторного використання частини даного типу. Це допомагає фіксувати тип, T
переданий як параметр.
function showType(args: T) { console.log(args) } showType("test") // Output: "test" showType(1) // Output: 1
Для побудови загального типу потрібно використовувати дужки та передавати T
як параметр.
Тут я використовую T
(ім'я залежить від вас), а потім showType
двічі викликати функцію з анотаціями різного типу, оскільки вона є загальною - її можна використовувати повторно.
interface GenericType { id: number name: T } function showType(args: GenericType) { console.log(args) } showType({ id: 1, name: "test" }) // Output: {id: 1, name: "test"} function showTypeTwo(args: GenericType) { console.log(args) } showTypeTwo({ id: 1, name: 4 }) // Output: {id: 1, name: 4}
Тут ми маємо ще один приклад, який має інтерфейс, GenericType
який отримує загальний тип T
. І оскільки він багаторазовий, ми можемо спершу назвати його рядком, а потім номером.
interface GenericType { id: T name: U } function showType(args: GenericType) { console.log(args) } showType({ id: 1, name: "test" }) // Output: {id: 1, name: "test"} function showTypeTwo(args: GenericType) { console.log(args) } showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] }) // Output: {id: "001", name: Array["This", "is", "a", "Test"]}
Загальний тип може отримувати кілька аргументів. Тут ми передаємо два параметри: T
і U
, а потім використовуємо їх як анотації типу для властивостей. Тим не менш, тепер ми можемо використовувати інтерфейс і наводити різні типи як аргументи.
Типи утиліт
TypeScript надає зручні вбудовані утиліти, які допомагають легко обробляти типи. Щоб використовувати їх, вам потрібно перейти до типу, який ви хочете перетворити.
Частково
Partial
Часткове дозволяє зробити всі властивості типу T
необов’язковими. Він додасть ?
позначку біля кожного поля.
interface PartialType { id: number firstName: string lastName: string } function showType(args: Partial) { console.log(args) } showType({ id: 1 }) // Output: {id: 1} showType({ firstName: "John", lastName: "Doe" }) // Output: {firstName: "John", lastName: "Doe"}
Як бачите, у нас є інтерфейс, PartialType
який використовується як анотація типу для параметрів, отриманих функцією showType()
. А щоб зробити властивості необов’язковими, ми повинні використовувати Partial
ключове слово та передавати тип PartialType
як аргумент. Тим не менш, тепер усі поля стають необов’язковими.
вимагається
Required
На відміну від цього Partial
, Required
програма робить усі властивості T
потрібного типу .
interface RequiredType { id: number firstName?: string lastName?: string } function showType(args: Required) { 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': firstName, lastName
Required
Утиліта зробить все властивості потрібно , навіть якщо ми їх необов'язковими перед використанням утиліти. І якщо властивість опущено, TypeScript видасть помилку.
Лише для читання
Readonly
Цей тип утиліти перетворить усі властивості типу T
, щоб зробити їх неможливо перепризначити новим значенням.
interface ReadonlyType { id: number name: string } function showType(args: Readonly) { args.id = 4 console.log(args) } showType({ id: 1, name: "Doe" }) // Error: Cannot assign to 'id' because it is a read-only property.
Тут ми використовуємо утиліту, Readonly
щоб зробити властивості ReadonlyType
неможливо перепризначити. Тим не менш, якщо ви спробуєте надати нове значення одному з цих полів, буде видано помилку.
Крім того, ви також можете використовувати ключове слово readonly
перед властивістю, щоб зробити його неможливо перепризначити.
interface ReadonlyType { readonly id: number name: string }
Виберіть
Pick
Це дозволяє створити новий тип із існуючої моделі T
, вибравши деякі властивості K
цього типу.
interface PickType { id: number firstName: string lastName: string } function showType(args: Pick) { 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'
Pick
дещо відрізняється від попередніх утиліт, які ми вже бачили. Він очікує двох параметрів - T
це тип, з якого потрібно вибрати елементи, та K
властивість, яку потрібно вибрати. Ви також можете вибрати кілька полів, розділивши їх |
символом pipe ( ).
Опустити
Omit
The Omit
utility is the opposite of the Pick
type. And instead of selecting elements, it will remove K
properties from the type T
.
interface PickType { id: number firstName: string lastName: string } function showType(args: Omit) { 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'
This utility is similar to the way Pick
works. It expects the type and the properties to omit from that type.
Extract
Extract
Extract
allows you to construct a type by picking properties that are present in two different types. The utility will extract from T
all properties that are assignable to U
.
interface FirstType { id: number firstName: string lastName: string } interface SecondType { id: number address: string city: string } type ExtractType = Extract // Output: "id"
Here, we have two types that have in common the property id
. And hence by using the Extract
keyword, we get back the field id
since it's present in both interfaces. And if you have more than one shared field, the utility will extract all similar properties.
Exclude
Unlike Extract
, the Exclude
utility will construct a type by excluding properties that are already present in two different types. It excludes from T
all fields that are assignable to U
.
interface FirstType { id: number firstName: string lastName: string } interface SecondType { id: number address: string city: string } type ExcludeType = Exclude // Output; "firstName" | "lastName"
As you can see here, the properties firstName
and lastName
are assignable to the SecondType
type since they are not present there. And by using the Extract
keyword, we get back these fields as expected.
Record
Record
This utility helps you to construct a type with a set of properties K
of a given type T
. Record
is really handy when it comes to mapping the properties of a type to another one.
interface EmployeeType { id: number fullname: string role: string } let employees: Record = { 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" }
The way Record
works is relatively simple. Here, it expects a number
as a type which is why we have 0, 1, and 2 as keys for the employees
variable. And if you try to use a string as a property, an error will be thrown. Next, the set of properties is given by EmployeeType
hence the object with the fields id, fullName, and role.
NonNullable
NonNullable
It allows you to remove null
and undefined
from the type T
.
type NonNullableType = string | number | null | undefined function showType(args: NonNullable) { 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'.
Here, we pass the type NonNullableType
as an argument to the NonNullable
utility which constructs a new type by excluding null
and undefined
from that type. That said, if you pass a nullable value, TypeScript will throw an error.
By the way, if you add the --strictNullChecks
flag to the tsconfig
file, TypeScript will apply non-nullability rules.
Mapped types
Mapped types allow you to take an existing model and transform each of its properties into a new type. Note that some utility types covered earlier are also mapped types.
type StringMap = { [P in keyof T]: string } function showType(arg: StringMap) { 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"}
StringMap
will transform whatever types that passed in into a string. That said, if we use it in the function showType()
, the parameters received must be a string - otherwise, an error will be thrown by TypeScript.
Type Guards
Type Guards allow you to check the type of a variable or an object with an operator. It's a conditional block that returns a type using typeof
, instanceof
, or in
.
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 ${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
As you can see, we have a normal JavaScript conditional block that checks the type of the argument received with typeof
. With that in place, you can now guard your type with this condition.
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
Like the previous example, this one is also a type guard that checks if the parameter received is part of the Foo
class or not and handles it consequently.
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
The in
operator allows you to check whether a property x
exists or not on the object received as a parameter.
Conditional Types
Conditional types test two types and select one of them depending on the outcome of that test.
type NonNullable = T extends null | undefined ? never : T
This example of the NonNullable
utility type checks if the type is null or not and handle it depending on that. And as you can note, it uses the JavaScript ternary operator.
Thanks for reading.
You can find other great content like this on my blog or follow me on Twitter to get notified.