[TypeScript] 关键字(一)

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,
};
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值