除了简单的用冒号去定义一个变量类型, 还有很多神奇操作. 但ts官网教程太庞大了, 我一般都是天马行空地想到需要什么类型,就去问chatGpt, 然后在官网去看看对应的api
总结一下常用的高级用法
联合类型和类型保护
什么是联合类型
当 TS 不确定一个联合类型的变量到底是哪个类型的时候,可以定义多种类型,例如,一个变量既支持 number 类型,又支持 string 类型
联合类型用 | 表示,如
const a: number | string = 'abc'
类型保护
如果一个变量是联合类型, 那在使用的时候如何判断这个变量具体的类型是什么呢, 有以下几种方法
typeof
基础类型还可以使用typeof来进行类型判断。 当type判断变量为"number", “string”, "boolean"或 "symbol"类型时,接下来的代码中该变量将被视为相关类型。 注意如果type判断变量为除四种外的其他类型,ts将无法识别,也就是该变量仍然被视为原有类型不变。
const a: number | string = 'abc'
const b = a.length // 报错
if(type a === string) {
const b = a.length // ok
}
const props : number | string = 1
if(typeof props === 'number'){
console.log(props/2)
}
instanceof类型保护
用法和typeof相同
in关键字
in类型保护检查对象是否具有特定的属性,并使用该属性区分不同的类型。
等式收缩保护器
function getValues(a: number | string, b: string) {
if(a === b) {
// this is where the narrowing takes place. narrowed to string
console.log(typeof a) // string
} else {
// if there is no narrowing, type remains unknown
console.log(typeof a) // number or string
}
}
console.log(getValues(2,"2"))
自定义类型保护
可以自己写一个自定义函数,用来判断变量的类型,这个函数返回一个布尔值。 返回值类型中使用 参数 is 类型 做定义。 当返回值为true时,任务参数 is 类型成立,否则不成立。
function isFish(pet: Fish | Bird): pet is Fish {
return (<Fish>pet).swim !== undefined;
}
上面代码中记录了一个自定义函数isFish,返回值类型为 pet is Fish ,也就是说当返回值为true时,ts认为pet是Fish类型,否则是Bird类型。 自定义函数的使用方式如下:
if (isFish(pet)) {
pet.swim();
}
else {
pet.fly();
}
剔除null与undefined
变量在未赋值时可能为null或undefined,这很常见。 但是在使用时就会报错,undefined上不包含该属性。 也就是变量类型为包含null/undefined的联合类型。 当一个变量的联合类型中含有null,可以直接通过判断去掉。
function f(sn: string | null): string {
if (sn == null) {
return "default";
}
else {
return sn;
}
}
为一个变量剔除null和undefined选项,也可以通过!进行快捷断言。
name!.charAt(0)
参考
blog.csdn.net/weixin_4580…
bbs.huaweicloud.com/blogs/35288…
交叉类型 &
联合类型 | 是指可以取几种类型中的任意一种,而交叉类型 & 是指把几种类型合并起来。 联合类型 | 是指可以取几种类型中的任意一种,而交叉类型 & 是指把几种类型合并起来。 // 交叉类型
let obj:{name: string, age:number} & {height: number};
obj = {name: 'll', age: 19, height: 20} // 属性必须全部要有,少了一个都报错
复用type定义的类型
type Point = {
x: number;
y: number;
};
type Coordinate = Point & {
z: number;
};
复用interface定义的类型
interface Point {
x: number;
y: number;
};
interface Coordinate extends Point {
z: number;
}
interface复用type定义的类型
type Point = {
x: number;
y: number;
};
interface Coordinate extends Point {
z: number;
}
type复用interface定义的类型
interface Point {
x: number;
y: number;
};
type Coordinate = Point & {
z: number;
};
Pick 挑选出指定属性,生成新对象类型
type UserInfo = Pick<Person, 'name' | 'age'>; // 挑选出 { name: string; age: number }
Omit 排除指定的属性,生成新的对象类型
type UserInfo2 = Omit<Person, 'id'>; // 排除 id,生成 { name: string; age: number }
Exclude 排除一些联合类型
type UserInfoKeys = Exclude<keyof Person, 'id'>; // 'name' | 'age'
Partial 将对象所有属性变为可选
type PartialPerson = Partial<Person>; // { name?: string; age?: number; id?: number }
Readonly 将对象所有属性变为只读
type ReadonlyPerson = Readonly<Person>; // { readonly name: string; readonly age: number; readonly id: number }
Record 生成对象类型,例如
type PersonMap = Record<number, Person>; // { [index: number]: Person }
枚举
普通枚举和常量枚举的区别
ts中普通枚举和常量枚举有什么区别
// 普通枚举
enum Color { Red, Green, Blue }
打印上面的Color,如下
{
"0": "Red",
"1": "Green",
"2": "Blue",
"Red": 0,
"Green": 1,
"Blue": 2
}
常量枚举:就是普通枚举前面加const,但编辑后枚举不见了,如果不使用枚举值就不会生成任何相关代码
总结:
-
普通枚举
enum A {...}
和常量枚举const enum A {...}
之间的区别主要在于TS
的编译结果上有所差别 -
普通枚举
enum A {...}
, 会将其编译为一个JS
对象, 对象内就是枚举成员和值的一个相互映射 -
常量枚举
const enum A {...}
, 编译后不会生成任何代码, 会删除TS
部分内容, 对于使用到的成员只会进行值的替换 -
普通枚举适用于需要动态修改枚举值的情况,或者在开发过程中需要根据业务逻辑动态调整枚举值时使用
-
常量枚举适用于需要确保枚举值在编译后保持不变的情况,比如在编写库或框架时,为了确保API的稳定性,需要固定枚举值,避免在后续开发中意外更改这些值(vite中的env变量就可以看成是常量枚举,因为他编译后就不会变化)
JavaScript中的四种枚举方式
保护枚举的值不被改变
Object.freeze和Object.seal
freeze 冻结一个对象,注意是浅冻结 seal 封闭一个对象
相同点: 都对变量进行了以下操作
- 设置Object.preventExtension(),禁止添加新属性(绝对存在)
- 设置configurable为false,禁止配置(绝对存在)
- 禁止更改访问器属性(getter和setter)
不同点: freeze多了一步操作:
- 设置writable为false,禁止修改(绝对存在)
换句话说,不同的地方如下:
- 用Object.freeze()冻结的对象中的现有属性是不可变的。
- 用Object.seal()密封的对象可以改变其现有属性。
const obj = {name:'lisa'}
Object.freeze(obj)
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
{
configurable: false,
writable: false
enumerable: true,
value: "lisa",
}
Object.seal(obj)
{
configurable: false,
writable: true
enumerable: true,
value: "lisa",
}
config false- write true ->false 遍历修改
Object.preventExtension()
只是禁止添加新的属性
configurable描述符
Object.freeze()和Object.seal(), Object.preventExtensions()
developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zhCN/docs/W…
JavaScript 中对象处理之Object.freeze 与 Object.seal
developer.mozilla.org/zh-CN/docs/…
对象的所有key值作为新的类型
To get a type that is a union keys of a variable you need to use keyof typeof variableName
.
const MY_OBJECT = {
'key': 'key val',
'anotherKey': 'anotherKey val',
};
type MY_OBJECT_KEYS = keyof typeof MY_OBJECT // "key" | "anotherKey"
stackoverflow.com/questions/5…
变量类型设置为interfacte类型中的某个属性的类型
新类型为 ( 其他类型['字段值']
interface Person {
name: '小米' | '小明'
age: number
}
interface Student {
mingzi: Person['name']
// 这个mingzi类型为Person中name的类型
}
stackoverflow.com/questions/7…
枚举作为对象的key类型
export enum colorsEnum{
red, blue, green
}
export type colorsInterface = {
[key in colorsEnum]: boolean;
};
let example: colorsInterface = {
[colorsEnum.red]: true,
[colorsEnum.blue]: false,
[colorsEnum.green]: true
};
如果不想使用所有的key,可以加?
export type colorsInterface = {
[key in colorsEnum]?: boolean;
};
let example: colorsInterface = {
[colorsEnum.red]: true,
[colorsEnum.blue]: false
};
stackoverflow.com/questions/3…
keyof 和 type keyof
ts Element implicitly has an any type because expression of type string can't be used to index type 这个错误一般出现获取对象里面的值的情况, 对应的key变量类型没有声明
interface Person {
name: string,
age: number,
}
const obj: Person = {
name: '张三',
age: 20,
};
const str: keyof Person = 'name'; // 另一个类型的key 类型
const str: type keyof obj = 'name'; // 另一个变量的key类型
console.log(obj[str]);
类型注解{ [key: string]: any }
在 TypeScript 中,{ [key: string]: any }
表示一个对象,其中键是字符串类型,而值可以是任意类型。
{}
表示这是一个对象类型。[key: string]
表示对象的键是字符串类型。 这种语法可以用于定义具有动态属性的对象。: any
表示对象的值可以是任意类型。
箭头函数的返回类型
interface AddTodoAction {
type: "ADD_TODO",
text: string
}
export const addTodo3 = (text: string) => <AddTodoAction>({
type: "ADD_TODO",
text
})
export const addTodo4 = function(text: string): AddTodoAction {
return {
type: "ADD_TODO",
text
}
}
export function addTodo5(text: string): AddTodoAction {
return {
type: "ADD_TODO",
text
}
}
// 箭头函数设置返回值类型, 一般参数类型和返回值类型都是分开定义的,比较灵活
export const addTodo6 = (text: string): AddTodoAction =>{
return {
type: "ADD_TODO",
text
}
}
stackoverflow.com/questions/4…
www.typescriptlang.org/docs/handbo…
try..catch..error类型的处理
一般捕获的error在ts中为any类型,可以用instanceof判断处理
class DivisionByZeroError extends Error {}
try {
// 假设这里有可能会抛出DivisionByZeroError的代码
const result = 10 / 0;
} catch (error) {
if (error instanceof DivisionByZeroError) {
console.error("Cannot divide by zero!");
} else {
// 处理其他类型的错误
}
}
也可以直接以error类型处理
try {
} catch (error as any as Error) {
}
stackoverflow.com/questions/5…
命名空间也可以看看
www.typescriptlang.org/docs/handbo…
其他参考
stackoverflow.com/questions/4…
www.cnblogs.com/ygyy/p/1819…
react 相关typescript
stackoverflow.com/questions/6…
stackoverflow.com/questions/7…
stackoverflow.com/questions/7…