- неизвестный тип функционирует как any, но не позволяет вызывать метод данных Typescript выдаст ошибку времени компиляции, так как мы используем строковую функцию без утверждения типа. Чтобы исправить это, правильный код будет выглядеть следующим образом
function readAny(val: unknown){
if( typeof val === 'string')
return val.trim();
}
- для проверки использования null/undefined, == например.
if(value == null) // check for both null and undefined
- пересечение типов (&) ведет себя как наследование в классах, то есть атрибуты одного типа наследуются другим типом, не вызывая дублирования
- пример:
type Point2d = {
x: number;
y:number;
}
type Point3d = Point2d & {
z:number;
}
const p1: Point2d = {x: 1, y:2}
const p2: Point3d = {x: 1, y:2, z: 9}
точка 3D имеет все члены точки 2D плюс член z. Все члены в типах пересечения являются обязательными. Если не передать «z» в типе Point3D, это приведет к ошибке.
- Тип Union определяется оператором pipe «|». Это означает, что тип может быть как отдельным типом, так и их комбинацией. Все свойства комбинации необязательны
interface A {
a1: string,
a2: string,
}
interface B {
b1: string,
b2: string;
}
type UnionAB = A | B;
const unionAB1: UnionAB = {
a1: 'xxx',
a2: 'xxx',
b1: 'xxx',
b2: 'xxx',
};
const unionAB2: UnionAB = {
a1: 'xxx',
a2: 'xxx',
};
const unionAB3: UnionAB = {
b1: 'xxx',
b2: 'xxx',
};
// Error
// Property 'a1' does not exist on type 'B'.
console.log(unionAB3.a1);
const unionAB4: UnionAB = {
a1: 'xxx',
a2: 'xxx',
b2: 'xxx',
};
// Error
// Property 'b1' does not exist on type 'UnionAB'.
// Property 'b1' does not exist on type 'A'.
console.log(unionAB4.b1);
// Error
// Type '{ a1: string; b2: string; }' is not assignable to type 'UnionAB'.
// Property 'b1' is missing in type '{ a1: string; b2: string; }' but required in type 'B'.
const unionAB5: UnionAB = {
a1: 'xxx',
b2: 'xxx',
};
- необязательные переменные в типе обозначаются символом «?» . Это означает, что значения могут передаваться или не передаваться. работает на переменных класса как пример:
type PointXd = {
x: number;
y:number;
z?:number;
}
const p1: PointXd = {x: 1, y:2}
const p2: PointXd = {x: 1, y:2, z: 5}
console.log(p1)
console.log(p2)
- Буквальные типы — Эта функция позволяет создавать набор значений отношений.
type Direction = "North" | "South" | "East" | "West";
Буквальные типы в этом случае создают также Type Guard вашего поля, так что компилятор может обнаружить ваши ошибки или опечатки.
let directionError: Direction = "east" // Type '"east"' is not assignable to type 'Direction'
let direction: Direction = "East" // OK
- Оператор keyof помогает нам извлекать свойства объекта, такие как литеральные типы
type Person = {
age: number;
phone: string;
}
type PersonKeys = keyof Person; // "age" | "phone"
usage with in operator to set all fields to number
type Student = {
[key in keyof Person]: number ;
}
const student: Student = {
age: 18,
phone: "1252672" // Type 'string' is not assignable to type 'number'
}
-
дискриминируемые типы
пример -
Утверждение not null может быть сделано с помощью оператора «!».
пример: https://dev.to/this-is-learning/typescript-tips-tricks-non-null-assertion-operator-21eb -
Интерфейс и тип в некотором роде одно и то же, но типы предлагают больше возможностей. & можно заменить на extends для интерфейса.
-
Интерфейс поддерживает объединение деклараций, которое аналогично объединению в типах. Если существуют два интерфейса с одинаковыми именами, то их тело объединяется.
пример:
interface Person {
name: string;
}
interface Person{
age: number
}
const person: Person = {name: 'Max', age: 27}; // merged into a single Person interface
console.log(person);
- никогда не видеть тип
- Когда класс реализует тип/интерфейс, он должен иметь все атрибуты, упомянутые в интерфейсе/типе. Это действует как пример чертежа:
type Person = {
age: number;
phone: string;
}
// Error below: Type 'Student' is missing the following properties from type 'Person': age, phone
class Student implements Person{
id: string
}
- окончательное присвоение(!) используется, чтобы сказать typescript, что значение будет определено, и вы должны убедиться, что оно определено.
let person: string
function test(){
person = "rubin"
}
test()
console.log(person) // error TS2454: Variable 'person' is used before being assigned.
Even though person is initialized inside the test function, typescript doesnot know this.
To tell typescript that this value will always be non null, add "!" and the error goes away
let person!: string
- Охрана типов используется с ключевым словом «is» и служит для утверждения, что значение имеет определенный тип.
type Rectangle ={
length: number,
breadth: number
}
type Square ={
size: number
}
type Shape = Rectangle | Square;
function isRectangle(shape: Shape): shape is Rectangle {
return "length" in shape && "breadth" in shape;
}
function isSquare(shape: Shape): shape is Square{
return "size" in shape;
}
function printArea(shape: Shape) {
if (isRectangle(shape)) {
console.log(shape.length * shape.breadth);
}
if(isSquare(shape)){
console.log(shape.size * shape.size);
}
}
Here we are telling typescript if the function returns true,
the value is of type "Person"
Notice: the guard can also be defined as
function isSquare(shape: Shape): boolean{
return "size" in shape;
}
However typescript wont know the shape is "Square" even if it returns true
so its best to use the above for type checking
- Абстрактный класс обычно используется для определения общего поведения производных классов. В отличие от обычного класса, абстрактный класс не может быть создан напрямую. Нереализованные методы должны быть реализованы и определены классами, которые его расширяют.
abstract class Logger{
abstract prefix(): string
log(message: string){
console.log(this.prefix() +":"+ message)
}
}
class ConsoleLogger extends Logger{
prefix(): string {
return "Console"
}
}
const logger = new ConsoleLogger()
logger.log("Hello")
- К объекту в js можно обращаться с помощью индексной подписи, т.е. Obj[key], подобно массиву. В typescript мы можем определить тип индекса при доступе к значениям объекта.
type Person= {
userName: string;
address: string;
}
const p1: Person = {
userName: 'alex123',
address: '123 Main St.',
}
const p2: Person = {
userName: 'ryan123',
address: '123 Main St.',
}
type PersonDictionary= {
[key: string]: Person
}
const persons: PersonDictionary = {
alex: p1,
ryan: p2
}
persons['alex'].userName = 'alex567'
console.log(persons['alex'])
-
Кортежи — это массивы с фиксированной длиной.
-
Общие ограничения используются для того, чтобы потребовать, чтобы общие параметры имели определенную структуру. Если вы не укажете их и попытаетесь получить доступ к свойству данных, typescript выдаст ошибку, так как не знает структуры данных.
const addFullName = <T>(obj: T) => {
return {...obj, fullName: `${obj.firstName} ${obj.lastName}`};
}
Здесь мы определили параметр типа generic T. Если мы попытаемся получить доступ к свойствам параметра,
даже если он существует, мы получим ошибку типа Property 'lastName' does not exist on type 'T'
. Мы можем исправить это, добавив ограничения generic, которые говорят typescript, что generic имеет эти свойства. Кроме того, он также требует, чтобы передаваемое значение имело свойства firstName
и lastName
.
type NamedVales = {firstName: string, lastName: string};
const addFullName = <T extends NamedVales>(obj: T) => {
return {...obj, fullName: `${obj.firstName} ${obj.lastName}`};
}
- Ключ
typeof
может быть использован для извлечения типа из существующих данных
const user = {
name: "Rubin",
age: 15,
address: "Kathmandu"
}
type UserType = typeof user // {name: string,age:number,address: string}
-Типы поиска используются для извлечения части из сложного типа и создания нового типа
type requestType = {
payload: {
name: string,
user: number,
roles: {
edit: boolean,
create: boolean,
read: boolean
}
},
params: {
id: number,
type: string
}
}
// if we want to use type of params as a type then
type Params = requestType["params"] // {id: number,type: string }
type Roles = requestType["payload"]["roles"] // roles: {edit: boolean,create: boolean,read: boolean}