ts基础知识复习
https://juejin.cn/post/6844903981227966471#heading-79
ts中的访问修饰符
public,任何地方
private,只能在类的内部访问
protected,能在类的内部访问和子类中访问
readonly,属性设置为只读
const和readonly的区别
const用于变量,readonly用于属性
const在运行时检查,readonly在编译时检查
使用const变量保存的数组,可以使用push,pop等方法。但是如果使用ReadonlyArray
枚举和常量枚举(const枚举)的区别
枚举会被编译时会编译成一个对象,可以被当作对象使用
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可以给Function/Array/Class做声明吗?
// 函数类型
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中的this和js中的this有什么差异?
不了解
ts中如何枚举联合类型的key?
type Name = { name: string }
type Age = { age: number }
type Union = Name | Age
type UnionKey
= P extends infer P ? keyof P : never
type T = UnionKey
ts中 ?.、??、!.、_、** 等符号的含义?
?. 可选链
?? ?? 类似与短路或,??避免了一些意外情况0,NaN以及"",false被视为false值。只有undefind,null被视为false值。
!. 在变量名后添加!,可以断言排除undefined和null类型
_ , 声明该函数将被传递一个参数,但您并不关心它
** 求幂
!:,待会分配这个变量,ts不要担心
// ??
let x = foo ?? bar();
// 等价于
let x = foo !== null && foo !== undefined ? foo : bar();
// !.
let a: string | null | undefined
a.length // error
a!.length // ok
什么是抗变、双变、协变和逆变?
Covariant 协变,TS对象兼容性是协变,父类 <= 子类,是可以的。子类 <= 父类,错误。
Contravariant 逆变,禁用strictFunctionTypes编译,函数参数类型是逆变的,父类 <= 子类,是错误。子类 <= 父类,是可以的。
Bivariant 双向协变,函数参数的类型默认是双向协变的。父类 <= 子类,是可以的。子类 <= 父类,是可以的。
ts中同名的interface或者同名的interface和class可以合并吗?
interface会合并
class不可以合并
如何使ts项目引入并识别编译为js的npm库包?
npm install @types/xxxx
自己添加描述文件
ts如何自动生成库包的声明文件?
可以配置tsconfig.json文件中的declaration和outDir
declaration: true, 将会自动生成声明文件
outDir: '', 指定目录
什么是泛型
泛型用来来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。简单的说,“泛型就是把类型当成参数”。
-?,-readonly 是什么含义
用于删除修饰符
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断言
const断言,typescript会为变量添加一个自身的字面量类型
对象字面量的属性,获得readonly的属性,成为只读属性
数组字面量成为readonly tuple只读元组
字面量类型不能被扩展(比如从hello类型到string类型)
// 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
type 和 interface 的区别
类型别名可以为任何类型引入名称。例如基本类型,联合类型等
类型别名不支持继承
类型别名不会创建一个真正的名字
类型别名无法被实现(implements),而接口可以被派生类实现
类型别名重名时编译器会抛出错误,接口重名时会产生合并
implements 与 extends 的区别
extends, 子类会继承父类的所有属性和方法。
implements,使用implements关键字的类将需要实现需要实现的类的所有属性和方法。
枚举和 object 的区别
枚举可以通过枚举的名称,获取枚举的值。也可以通过枚举的值获取枚举的名称。
object只能通过key获取value
数字枚举在不指定初始值的情况下,枚举值会从0开始递增。
虽然在运行时,枚举是一个真实存在的对象。但是使用keyof时的行为却和普通对象不一致。必须使用keyof typeof才可以获取枚举所有属性名。
never, void 的区别
never,never表示永远不存在的类型。比如一个函数总是抛出错误,而没有返回值。或者一个函数内部有死循环,永远不会有返回值。函数的返回值就是never类型。
void, 没有显示的返回值的函数返回值为void类型。如果一个变量为void类型,只能赋予undefined或者null。
unknown, any的区别
unknown类型和any类型类似。与any类型不同的是。unknown类型可以接受任意类型赋值,但是unknown类型赋值给其他类型前,必须被断言
如何在 window 扩展类型
declare global {
interface Window {
myCustomFn: () => void;
}
}
复杂的类型推导题目
implement UnionToIntersection
type A = UnionToIntersection<{a: string} | {b: string} | {c: string}>
// {a: string} & {b: string} & {c: string}
// 实现UnionToIntersection
type UnionToIntersection =
(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
implement ToNumber
type A = ToNumber<'1'> // 1
type B = ToNumber<'40'> // 40
type C = ToNumber<'0'> // 0
// 实现ToNumber
type ToNumber
T extends `${R['length']}` ? R['length'] : ToNumber
type A = Add<1, 2> // 3
type B = Add<0, 0> // 0
// 实现ADD
type NumberToArray
type Add