TS中的一些符号
!断言操作符
const obj = {
name: 'decademo'
}
const a = obj!.name;
当你确定obj.name
一定存在时(不为null/undefined),使用!表示强制解析,消除编辑器报错。
?.链判断运算符
const checkId = response.result.data.checkId;
// 有时候从response中获取到的数据为空,即response.result.data == null
// 那么将会报错: checkId is not defined
// 正确的写法
const checkId = (response && response.result && response.result.data &&
response.result.data.checkId) || '';
// 使用 ?. 简化代码
const checkId = response?.result?.data?.checkId || '';
TS中的一些关键字
type
const x: number = 11; // ts写法 表示x为number类型
// or
type num = number; // 声明num可以表示为number类型
const x1: num = 12; // 表示x1为num类型,即number类型
// type关键字更广泛的用途在于 表示更复杂的数据类型
type userObj = { name: string }; // 对象
type getName = () => string; // 函数
type data = [ number, string ]; // 元组
type numOrFun = number | getName; // 联合类型
type SetUser = (name: string, age: number) => void;
interface
interface和type的用法差不多
interface SetUser = {
(name: string, age: number) => void;
}
区别在于,语法不同
- interface类似于java中的接口,声明式
- type类似于变量定义与赋值,定义式
typeof
- 在JS中,typeof可以判断一个变量的基础数据类型
- 在TS中,它还可以获取一个变量的声明类型
const obj = { a: '1' );
// js中
console.log(typeof obj === 'object'); // true
// ts中
type Foo = typeof obj; // type Foo = { a: string }
keyof
keyof操作符可以用于获取某种类型的所有键,返回一个联合类型
type obj = { a: string; b: string };
type Foo = keyof obj; // type Foo = 'a' | 'b'
keyof使用场景
定义一个获取函数属性的函数
function prop(obj: object, key: string) {
return obj[key];
}
我们希望传入对象obj和key,以获取obj[key]的值,并且为obj和key设置了类型。
但是TS编辑器依然会报错:
lement implicitly has an ‘any’ type because expression of type ‘string’ can’t be used to index type ‘{}’.
元素隐式拥有any类型,因为string类型不能被用于索引{}类型,可以暴力解决这个问题:
function prop(obj: object, key: string) {
return (obj as any)[key];
}
或者使用keyof操作符:
function prop<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
keyof与对象的数值属性
当对象具有数值属性时,想访问其值,可能会有些麻烦:
class ClassWithNumericProperty {
[1]: string = "Semlinker";
}
let classWithNumeric = new ClassWithNumericProperty();
console.log(`${classWithNumeric[1]}`);
但是这样多少有些不安全,因为你得使用`${}`的形式包裹你的变量,并且classWithNumeric[1]
的写法容易联想到数组,但它其实是一个对象的键值。
我们可以先试用enum代替数字类型的键,再用keyof包装访问模式:
enum Currency {
CNY = 6,
EUR = 8,
USD = 10
}
const CurrencyName = {
[Currency.CNY]: "人民币",
[Currency.EUR]: "欧元",
[Currency.USD]: "美元"
};
console.log(`CurrencyName[Currency.CNY] = ${CurrencyName[Currency.CNY]}`);
console.log(`CurrencyName[6] = ${CurrencyName[6]}`);
// 再使用keyof包装
function getCurrencyName<T, K extends keyof T>(key: K, map: T): T[k] {
return map[key];
}
console.log('name = ', getCurrencyName(Currency.CNY, CurrencyName));
in
in 用于遍历枚举类型
type Keys = 'a' | 'b' | 'c';
type obj = {
[ T in Keys]: string;
}
// in 遍历 Keys, 并为每个值赋予 string 类型
// type obj = {
// a: string,
// b: string,
// c: string
// }
TS中的一些内置类型
Partial<T>
可将T类型中的属性变成可选的(浅Partial)
// 对于类型 UserInfo
interface UserInfo {
id: string;
name: string;
}
// 定义UserInfo类型的变量时,若缺少id属性或name属性,则会报错
const Mike: UserInfo = { name: 'Mike' };
// error: Property 'id' is missing in type '{ name: string; }' but required in type 'UserInfo'
// 使用Partial<T>
type NewUserInfo = Partial<UserInfo>;
const Mike: NewUserInfo = {
name: 'Mike'
}// 不报错
// Partial<UserInfo> 相当于
interface NewUserInfo {
id?: string;
name?: string;
}
// 但是Partial<T> 存在局限性: 只支持第一层的属性,如果接口定义存在多层嵌套,即使使用了partial<T>,也无法影响第二层及更深层的属性
解决方案: 自定义DeepPartial
type DeepPartial<T> = {
[U in keyof T]?: T[U] extends object
? DeepPartial<T[U]>
: T[U]
};
Required<T>
Required用于将T类型的所有属性变成必选
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
// error: Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.
Readonly<T>
Readonly用于将T类型中所有的属性设置为只读模式(不可修改)
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: "Delete inactive users".
};
todo.title = "Hello";
// error: Connot assign to 'title' because it is a read-only property.
Record<Keys, Type>
Keys是一个联合类型(一个或多个), Record根据Keys中所有可能的值来设置key,并且value的类型都是Type类型
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" },
};
Pick<Type, Keys>
Pick用于从Type类型中挑选部分属性出来,将要挑选的属性由Keys列出
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};