обзор базовых знаний
😊 Модификаторы доступа в ts
- публично, где угодно
- закрытый, доступный только внутри класса
- защищенный, доступен внутри класса и в подклассах
- readonly, свойство устанавливается только для чтения
😊 Разница между const и readonly
- const для переменных, только для чтения для свойств
- const проверяется во время выполнения, readonly проверяется во время компиляции
- Массивы, сохраненные с константными переменными, могут использовать push, pop и другие методы. Но если вы используете
ReadonlyArray<number>Объявленный массив не может использовать push, pop и другие методы.
😊 Отличие перечисления от перечисления констант (const enumeration)
- Перечисления компилируются в объект при компиляции, который можно использовать как объект
- перечисления const удаляются во время компиляции ts, чтобы избежать дополнительных потерь производительности.
// 普通枚举
enum Witcher {
Ciri = 'Queen',
Geralt = 'Geralt of Rivia'
}
function getGeraltMessage(arg: {[key: string]: string}): string {
return arg.Geralt
}
getGeraltMessage(Witcher) // Geralt of Rivia
// const枚举
const enum Witcher {
Ciri = 'Queen',
Geralt = 'Geralt of Rivia'
}
const witchers: Witcher[] = [Witcher.Ciri, Witcher.Geralt]
// 编译后
// const witchers = ['Queen', 'Geralt of Rivia'
😊 Может ли интерфейс в ts объявлять функцию/массив/класс?
// 函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
// Array
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
// Class, constructor存在于类的静态部分,所以不会检查
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
В чем разница между этим в ts и этим в js?
не понимаю
😊 Как перебрать ключи типа union в ts?
type Name = { name: string }
type Age = { age: number }
type Union = Name | Age
type UnionKey<P> = P extends infer P ? keyof P : never
type T = UnionKey<Union>
😊 Что означают ?., ??, !., _, ** и другие символы в ts?
- ?.Дополнительная цепочка
- ?? ?? Аналогично короткому замыканию или, ?? позволяет избежать некоторых непредвиденных ситуаций 0, NaN и "", false рассматриваются как ложные значения. Только undefined, null считаются ложными значениями.
- !. Добавьте ! после имени переменной в предикат, чтобы исключить неопределенные и нулевые типы.
- _, объявляет, что функции будет передан аргумент, но вас это не волнует
- ** возведение в степень
- !:, назначьте эту переменную позже, не волнуйтесь
// ??
let x = foo ?? bar();
// 等价于
let x = foo !== null && foo !== undefined ? foo : bar();
// !.
let a: string | null | undefined
a.length // error
a!.length // ok
😊 Что такое инвариант, бивариант, ковариант и контравариант?
- Ковариантно-ковариантно, совместимость объектов TS является ковариантной, родительский класс
- Контравариант, отключен
strictFunctionTypesКомпиляция, типы параметров функции контравариантны, родительский класс - Бивариантный Двусторонний ковариантный, тип параметров функции по умолчанию двусторонний ковариантный. Родительский класс
😊 Можно ли объединить одноименный интерфейс или одноименный интерфейс и класс в ts?
- интерфейс будет сливаться
- классы нельзя объединять
😊 Как заставить проект ts импортировать и распознавать пакет библиотеки npm, скомпилированный в js?
npm install @types/xxxx- Добавьте файл описания самостоятельно
😊 Как ts автоматически генерирует файл объявления пакета библиотеки?
можно настроитьtsconfig.jsonв файлеdeclarationа такжеoutDir
- декларация: true, будут автоматически генерироваться файлы декларации
- outDir: '', укажите каталог
😊 Что такое дженерики
Дженерики используются для создания повторно используемых компонентов, компонент может поддерживать несколько типов данных. Это позволяет пользователям использовать компоненты с собственными типами данных.Проще говоря, «Generic принимает типы в качестве параметров».
😊 -?, что значит -только для чтения
для удаления модификаторов
type A = {
a: string;
b: number;
}
type B = {
[K in keyof A]?: A[K]
}
type C = {
[K in keyof B]-?: B[K]
}
type D = {
readonly [K in keyof A]: A[K]
}
type E = {
-readonly [K in keyof A]: A[K]
}
😊 TS основан на совместимом типе структуры
Совместимость типов в TypeScript основана на структурах, а не на именах. Приведенный ниже код отлично работает в ts, но выдает ошибку на номинальном языке, таком как java.
interface Named { name: string }
class Person {
name: string
}
let p: Named
// ok
p = new Person()
😊 константное утверждение
const, машинописный текст добавит литерал собственного типа к переменной
- Литеральные свойства объекта, получить свойства только для чтения, стать свойствами только для чтения
- Литералы массива становятся кортежами только для чтения
- Литеральные типы не могут быть расширены (например, от приветствия до строки)
// type '"hello"'
let x = "hello" as const
// type 'readonly [10, 20]'
let y = [10, 20] as const
// type '{ readonly text: "hello" }'
let z = { text: "hello" } as const
😊 Разница между типом и интерфейсом
- Псевдонимы типов могут вводить имена для любого типа. такие как примитивные типы, типы объединения и т. д.
- Псевдонимы типов не поддерживают наследование
- Псевдонимы типов не создают настоящее имя
- Псевдонимы типов не могут быть реализованы, тогда как интерфейсы могут быть реализованы производными классами.
- Компилятор выдаст ошибку, если псевдоним типа имеет такое же имя, и объединится, если интерфейс имеет такое же имя.
😊 Разница между реализациями и расширениями
- extends, подкласс унаследует все свойства и методы родительского класса.
- реализует, класс, использующий ключевое слово, должен будет реализовать все свойства и методы класса, который необходимо реализовать.
😊 Разница между перечислением и объектом
- Перечисления могут получить значение перечисления по имени перечисления. Имя перечисления также можно получить из значения перечисления.
- объект может получить значение только по ключу
- Числовые перечисления будут увеличиваться с 0 без указания начального значения.
- Хотя во время выполнения перечисление является реальным объектом. Но поведение при использовании keyof несовместимо с обычными объектами. Вы должны использовать keyof typeof, чтобы получить все имена свойств перечисления.
😊 Разница между никогда и пустотой
- никогда, никогда не представляет тип, который никогда не существует. Например, функция всегда выдает ошибку, не возвращая значения. Или внутри функции есть бесконечный цикл, который никогда не возвращает значение. Возвращаемое значение функции имеет тип никогда.
- void, возвращаемое значение функции без явного возвращаемого значения имеет тип void. Если переменная имеет тип void, ей можно присвоить только значение undefined или null.
Разница между неизвестным и любым
Неизвестный тип аналогичен любому типу. В отличие от любого типа. Неизвестный тип может принимать любое присвоение типа, но неизвестный тип должен быть утвержден до того, как он будет присвоен другим типам.
😊 Как расширить текст в окне
declare global {
interface Window {
myCustomFn: () => void;
}
}
сложные задачи вывода типов
🤔 реализовать UnionToIntersection
type A = UnionToIntersection<{a: string} | {b: string} | {c: string}>
// {a: string} & {b: string} & {c: string}
// 实现UnionToIntersection<T>
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
// https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
// https://jkchao.github.io/typescript-book-chinese/tips/infer.html#%E4%B8%80%E4%BA%9B%E7%94%A8%E4%BE%8B
😊 реализовать ToNumber
type A = ToNumber<'1'> // 1
type B = ToNumber<'40'> // 40
type C = ToNumber<'0'> // 0
// 实现ToNumber
type ToNumber<T extends string, R extends any[] = []> =
T extends `${R['length']}` ? R['length'] : ToNumber<T, [1, ...R]>;
😊 реализовать Add
type A = Add<1, 2> // 3
type B = Add<0, 0> // 0
// 实现ADD
type NumberToArray<T, R extends any[]> = T extends R['length'] ? R : NumberToArray<T, [1, ...R]>
type Add<T, R> = [...NumberToArray<T, []>, ...NumberToArray<R, []>]['length']
😊 реализовать SmallerThan
type A = SmallerThan<0, 1> // true
type B = SmallerThan<1, 0> // false
type C = SmallerThan<10, 9> // false
// 实现SmallerThan
type SmallerThan<N extends number, M extends number, L extends any[] = [], R extends any[] = []> =
N extends L['length'] ?
M extends R['length'] ? false : true
:
M extends R['length'] ? false : SmallerThan<N, M, [1, ...L], [1, ...R]>;
😊 реализовать LargerThan
type A = LargerThan<0, 1> // false
type B = LargerThan<1, 0> // true
type C = LargerThan<10, 9> // true
// 实现LargerThan
type LargerThan<N extends number, M extends number, L extends any[] = [], R extends any[] = []> =
N extends L['length'] ?
false : M extends R['length'] ?
true : LargerThan<N, M, [1, ...L], [1, ...R]>;
😊 реализовать IsAny
type A = IsAny<string> // false
type B = IsAny<any> // true
type C = IsAny<unknown> // false
type D = IsAny<never> // false
// 实现IsAny
type IsAny<T> = true extends (T extends never ? true : false) ?
false extends (T extends never ? true : false) ?
true
:
false
:
false;
// 更简单的实现
type IsAny<T> = 0 extends (T & 1) ? true : false;
😊 реализовать фильтр
type A = Filter<[1,'BFE', 2, true, 'dev'], number> // [1, 2]
type B = Filter<[1,'BFE', 2, true, 'dev'], string> // ['BFE', 'dev']
type C = Filter<[1,'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']
// 实现Filter
type Filter<T extends any[], A, N extends any[] = []> =
T extends [infer P, ...infer Q] ?
0 extends (P & 1) ? Filter<Q, A, [...N, P]> :
P extends A ? Filter<Q, A, [...N, P]> : Filter<Q, A, N>
: N;
😊 реализовать TupleToString
type A = TupleToString<['a']> // 'a'
type B = TupleToString<['B', 'F', 'E']> // 'BFE'
type C = TupleToString<[]> // ''
// 实现TupleToString
type TupleToString<T extends any[], S extends string = '', A extends any[] = []> =
A['length'] extends T['length'] ? S : TupleToString<T, `${S}${T[A['length']]}`, [1, ...A]>
😊 реализовать RepeatString
type A = RepeatString<'a', 3> // 'aaa'
type B = RepeatString<'a', 0> // ''
// 实现RepeatString
type RepeatString<T extends string, C extends number, S extends string = '', A extends any[] = []> =
A['length'] extends C ? S : RepeatString<T, C, `${T}${S}`, [1, ...A]>
😊 реализовать Push
type A = Push<[1,2,3], 4> // [1,2,3,4]
type B = Push<[1], 2> // [1, 2]
type C = Push<[], string> // [string]
// 实现Push
type Push<T extends any[], I> = T extends [...infer P] ? [...P, I] : [I]
😊 реализовать плоский
type A = Flat<[1,2,3]> // [1,2,3]
type B = Flat<[1,[2,3], [4,[5,[6]]]]> // [1,2,3,4,5,6]
type C = Flat<[]> // []
// 实现Flat
type Flat<T extends any[]> =
T extends [infer P, ...infer Q] ?
P extends any[] ? [...Flat<P>, ...Flat<Q>] : [P, ...Flat<Q>]
: [];
😊 реализовать Shift
type A = Shift<[1,2,3]> // [2,3]
type B = Shift<[1]> // []
type C = Shift<[]> // []
// 实现Shift
type Shift<T extends any[]> = T extends [infer P, ...infer Q] ? [...Q] : [];
😊 реализовать Repeat
type A = Repeat<number, 3> // [number, number, number]
type B = Repeat<string, 2> // [string, string]
type C = Repeat<1, 1> // [1, 1]
type D = Repeat<0, 0> // []
// 实现Repeat
type Repeat<T, C, R extends any[] = []> =
R['length'] extends C ? R : Repeat<T, C, [...R, T]>
😊 реализовать ReverseTuple
type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string]
type B = ReverseTuple<[1,2,3]> // [3,2,1]
type C = ReverseTuple<[]> // []
// 实现ReverseTuple
type ReverseTuple<T extends any[], A extends any[] = []> =
T extends [...infer Q, infer P] ?
A['length'] extends T['length'] ? A : ReverseTuple<Q, [...A, P]>
: A;
😊 реализовать UnwrapPromise
type A = UnwrapPromise<Promise<string>> // string
type B = UnwrapPromise<Promise<null>> // null
type C = UnwrapPromise<null> // Error
// 实现UnwrapPromise
type UnwrapPromise<T> = T extends Promise<infer P> ? P : Error;
😊 реализовать LengthOfString
type A = LengthOfString<'BFE.dev'> // 7
type B = LengthOfString<''> // 0
// 实现LengthOfString
type LengthOfString<T extends string, A extends any[] = []> =
T extends `${infer P}${infer Q}` ? LengthOfString<Q, [1, ...A]> : A['length']
😊 реализовать StringToTuple
type A = StringToTuple<'BFE.dev'> // ['B', 'F', 'E', '.', 'd', 'e','v']
type B = StringToTuple<''> // []
// 实现
type StringToTuple<T extends string, A extends any[] = []> =
T extends `${infer K}${infer P}` ? StringToTuple<P, [...A, K]> : A;
😊 реализовать LengthOfTuple
type A = LengthOfTuple<['B', 'F', 'E']> // 3
type B = LengthOfTuple<[]> // 0
// 实现
type LengthOfTuple<T extends any[], R extends any[] = []> =
R['length'] extends T['length'] ? R['length'] : LengthOfTuple<T, [...R, 1]>
😊 реализовать LastItem
type A = LastItem<[string, number, boolean]> // boolean
type B = LastItem<['B', 'F', 'E']> // 'E'
type C = LastItem<[]> // never
// 实现LastItem
type LastItem<T> = T extends [...infer P, infer Q] ? Q : never;
😊 реализовать FirstItem
type A = FirstItem<[string, number, boolean]> // string
type B = FirstItem<['B', 'F', 'E']> // 'B'
// 实现FirstItem
type FirstItem<T> = T extends [infer P, ...infer Q] ? P : never;
😊 реализовать FirstChar
type A = FirstChar<'BFE'> // 'B'
type B = FirstChar<'dev'> // 'd'
type C = FirstChar<''> // never
// 实现FirstChar
type FirstChar<T> = T extends `${infer P}${infer Q}` ? P : never;
😊 реализовать Pick
type Foo = {
a: string
b: number
c: boolean
}
type A = MyPick<Foo, 'a' | 'b'> // {a: string, b: number}
type B = MyPick<Foo, 'c'> // {c: boolean}
type C = MyPick<Foo, 'd'> // Error
// 实现MyPick<T, K>
type MyPick<T, K extends keyof T> = {
[Key in K]: T[Key]
}
😊 реализовать только для чтения
type Foo = {
a: string
}
const a:Foo = {
a: 'BFE.dev',
}
a.a = 'bigfrontend.dev'
// OK
const b:MyReadonly<Foo> = {
a: 'BFE.dev'
}
b.a = 'bigfrontend.dev'
// Error
// 实现MyReadonly
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
😊 реализовать запись
type Key = 'a' | 'b' | 'c'
const a: Record<Key, string> = {
a: 'BFE.dev',
b: 'BFE.dev',
c: 'BFE.dev'
}
a.a = 'bigfrontend.dev' // OK
a.b = 123 // Error
a.d = 'BFE.dev' // Error
type Foo = MyRecord<{a: string}, string> // Error
// 实现MyRecord
type MyRecord<K extends number | string | symbol, V> = {
[Key in K]: V
}
😊 реализовать Исключить
type Foo = 'a' | 'b' | 'c'
type A = MyExclude<Foo, 'a'> // 'b' | 'c'
type B = MyExclude<Foo, 'c'> // 'a' | 'b
type C = MyExclude<Foo, 'c' | 'd'> // 'a' | 'b'
type D = MyExclude<Foo, 'a' | 'b' | 'c'> // never
// 实现 MyExclude<T, K>
type MyExclude<T, K> = T extends K ? never : T;
😊 реализовать Extract
type Foo = 'a' | 'b' | 'c'
type A = MyExtract<Foo, 'a'> // 'a'
type B = MyExtract<Foo, 'a' | 'b'> // 'a' | 'b'
type C = MyExtract<Foo, 'b' | 'c' | 'd' | 'e'> // 'b' | 'c'
type D = MyExtract<Foo, never> // never
// 实现MyExtract<T, U>
type MyExtract<T, U> = T extends U ? T : never
😊 реализуем Omit
type Foo = {
a: string
b: number
c: boolean
}
type A = MyOmit<Foo, 'a' | 'b'> // {c: boolean}
type B = MyOmit<Foo, 'c'> // {a: string, b: number}
type C = MyOmit<Foo, 'c' | 'd'> // {a: string, b: number}
// 实现MyOmit
type MyOmit<T, K extends number | string | symbol> = {
[Key in Exclude<keyof T, K>]: T[Key]
}
type MyOmit<T, K extends number | string | symbol> = Pick<T, Exclude<keyof T, K>>
😊 реализовать NonNullable
type Foo = 'a' | 'b' | null | undefined
type A = MyNonNullable<Foo> // 'a' | 'b'
// 实现NonNullable
type MyNonNullable<T> = T extends null | undefined ? never : T;
😊 реализовать параметры
type Foo = (a: string, b: number, c: boolean) => string
type A = MyParameters<Foo> // [a:string, b: number, c:boolean]
type B = A[0] // string
type C = MyParameters<{a: string}> // Error
// 实现MyParameters<T>
type MyParameters<T extends (...params: any[]) => any> =
T extends (...params: [...infer P]) => any ? P : never
😊 реализовать ConstructorParameters
class Foo {
constructor (a: string, b: number, c: boolean) {}
}
type C = MyConstructorParameters<typeof Foo>
// [a: string, b: number, c: boolean]
// 实现MyConstructorParameters<T>
type MyConstructorParameters<T extends new (...params: any[]) => any> =
T extends new (...params: [...infer P]) => any ? P : never
😊 реализовать тип возврата
type Foo = () => {a: string}
type A = MyReturnType<Foo> // {a: string}
// 实现MyReturnType<T>
type MyReturnType<T extends (...params: any[]) => any> =
T extends (...params: any[]) => infer P ? P : never;
😊 реализовать InstanceType
class Foo {}
type A = MyInstanceType<typeof Foo> // Foo
type B = MyInstanceType<() => string> // Error
// 实现MyInstanceType<T>
type MyInstanceType<T extends new (...params: any[]) => any> =
T extends new (...params: any[]) => infer P ? P : never;
😊 реализовать тип этого параметра
function Foo(this: {a: string}) {}
function Bar() {}
type A = MyThisParameterType<typeof Foo> // {a: string}
type B = MyThisParameterType<typeof Bar> // unknown
// 实现MyThisParameterType<T>
type MyThisParameterType<T extends (this: any, ...params: any[]) => any> =
T extends (this: infer P, ...params: any[]) => any ? P : unknown;
😊 реализовать TupleToUnion
type Foo = [string, number, boolean]
type Bar = TupleToUnion<Foo> // string | number | boolean
// 实现TupleToUnion<T>
type TupleToUnion<T extends any[], R = T[0]> =
T extends [infer P, ...infer Q] ? TupleToUnion<Q, R | P> : R;
// 其他回答
type TupleToUnion<T extends any[]> = T[number]
😊 реализовать частично
type Foo = {
a: string
b: number
c: boolean
}
// below are all valid
const a: MyPartial<Foo> = {}
const b: MyPartial<Foo> = {
a: 'BFE.dev'
}
const c: MyPartial<Foo> = {
b: 123
}
const d: MyPartial<Foo> = {
b: 123,
c: true
}
const e: MyPartial<Foo> = {
a: 'BFE.dev',
b: 123,
c: true
}
// 实现MyPartial<T>
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
😊 Обязательно
// all properties are optional
type Foo = {
a?: string
b?: number
c?: boolean
}
const a: MyRequired<Foo> = {}
// Error
const b: MyRequired<Foo> = {
a: 'BFE.dev'
}
// Error
const c: MyRequired<Foo> = {
b: 123
}
// Error
const d: MyRequired<Foo> = {
b: 123,
c: true
}
// Error
const e: MyRequired<Foo> = {
a: 'BFE.dev',
b: 123,
c: true
}
// valid
// 实现MyRequired<T>
type MyRequired<T> = {
[K in keyof T]-?: T[K]
}
😊 реализовать LastChar
type A = LastChar<'BFE'> // 'E'
type B = LastChar<'dev'> // 'v'
type C = LastChar<''> // never
// 实现FirstChar<T>
type LastChar<T extends string, A extends string[] = []> =
T extends `${infer P}${infer Q}` ? LastChar<Q, [...A, P]> :
A extends [...infer L, infer R] ? R : never
;
😊 реализовать IsNever
// https://stackoverflow.com/questions/53984650/typescript-never-type-inconsistently-matched-in-conditional-type
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#v
type A = IsNever<never> // true
type B = IsNever<string> // false
type C = IsNever<undefined> // false
// 实现IsNever<T>
type IsNever<T> = [T] extends [never] ? true : false;
😊 реализовать KeysToUnion
type A = KeyToUnion<{
a: string;
b: number;
c: symbol;
}>
// 'a' | 'b' | 'c'
// 实现KeyToUnion
type KeyToUnion<T> = {
[K in keyof T]: K;
}[keyof T]
😊 реализовать ValuesToUnion
type A = ValuesToUnion<{
a: string;
b: number;
c: symbol;
}>
// string | number | symbol
// ValuesToUnion
type ValuesToUnion<T> = T[keyof T]
FindIndex<T, E>
type IsAny<T> = 0 extends (T & 1) ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
type TwoAny<A, B> = IsAny<A> extends IsAny<B> ? IsAny<A> : false;
type TwoNever<A, B> = IsNever<A> extends IsNever<B> ? IsNever<A> : false;
type SingleAny<A, B> = IsAny<A> extends true ? true : IsAny<B>
type SingleNever<A, B> = IsNever<A> extends true ? true : IsNever<B>
type FindIndex<T extends any[], E, A extends any[] = []> =
T extends [infer P, ...infer Q] ?
TwoAny<P, E> extends true ?
A['length']
:
TwoNever<P, E> extends true ?
A['length']
:
SingleAny<P, E> extends true ?
FindIndex<Q, E, [1, ...A]>
:
SingleNever<P, E> extends true ?
FindIndex<Q, E, [1, ...A]>
:
P extends E ? A['length'] : FindIndex<Q, E, [1, ...A]>
:
never
implement Trim
type A = Trim<' BFE.dev'> // 'BFE'
type B = Trim<' BFE. dev '> // 'BFE. dev'
type C = Trim<' BFE . dev '> // 'BFE . dev'
type StringToTuple<T extends string, A extends any[] = []> =
T extends `${infer K}${infer P}` ? StringToTuple<P, [...A, K]> : A;
type TupleToString<T extends any[], S extends string = '', A extends any[] = []> =
A['length'] extends T['length'] ? S : TupleToString<T, `${S}${T[A['length']]}`, [1, ...A]>
type Trim<T extends string, A extends any[] = StringToTuple<T>> =
A extends [infer P, ...infer Q] ?
P extends ' ' ?
Trim<T, Q>
:
A extends [...infer M, infer N] ?
N extends ' ' ?
Trim<T, M>
:
TupleToString<A>
:
''
:
'';