ts问题小总结
作为一个前端小白,刚刚开始学习TS的时候,遇到了许多疑惑,但是对于学过后端的朋友来说可能是小问题,所以酌情阅读~
区别
1.any和unkown的区别
any表示任意类型, 可以被任何类型分配,也可以分配给任何类型
unkwon表示未知类型, 可以被任何类型分配,不能分配给任何类型
首先看any类型
// 1. 把any类型分配给其他类型
let val:any
let val_any:any = val;
let val_unknown:unknown = val;
let val_void:void = val;
let val_undefined:undefined = val;
let val_null:null = val;
let val_number:number = val;
let val_string:string = val;
let val_boolean:boolean = val;
// 报错:不能将类型“any”分配给类型“never”
// let val_never:never = val;
// 2.把其他类型分配给1any
val = '';
val = 1;
val = true;
val = null;
val = undefined;
// 报错:“unknown”仅表示类型,但在此处却作为值使用
// val = unknown;
// 报错:“never”仅表示类型,但在此处却作为值使用
// val = never;
// 报错:“any”仅表示类型,但在此处却作为值使用
// val = any;
// 报错:应为表达式
// val = void;
然后看看unknown类型
// 1.把unknown类型分配给其他类型
let val: unknown;
let val_any:any = val;
let val__unknown:unknown = val;
// 报错:不能将类型“unknown”分配给类型“string”
let val_string:string = val;
// 报错:不能将类型“unknown”分配给类型“number”
let val_number:number = val;
// 报错:不能将类型“unknown”分配给类型“boolean”
let val_boolean:boolean = val;
// 报错:不能将类型“unknown”分配给类型“null”
let val_null:null = val;
// 报错:不能将类型“unknown”分配给类型“undefined”
let val_undefined:undefined = val;
// 2.把其他类型分配给unknown类型
val = '';
val = 0;
val = true;
val = undefined;
val = null;
// 和any一样,报错
val = void;
val = any;
val = unknown;
val = never;
代码规范,any虽然可以代表任意类型,但是能不用就不要用,这是默认的代码规范问题,不要用成anyscript!
与any任意类型相比,因为unknown是未知类型,所以只能进行!!,!,?,typeof,instanceof等有限操作
2. 数组和元组的区别
如果数组的类型在[]前面,那么表示该数组全部都是该类型
如果数组的类型在[]内部(严格限制类型和长度的元组),那么表示该数组的第x个元素是该类型
首先,数组的类型在[]前面
// 此时表示数组内部都是数字类型
// let arr:number[] = [1,2,3];
let arr:(number | string)[] = ['s',3,'a'];
let arr:any[] = ['a',2,true];
此时来看看数组的类型在[]内部的用法,此时就是 元组
!
// 报错:不能将类型“[number, number, number]”分配给类型“[number]”。源具有 3 个元素,但目标仅允许 1 个
// let arr:[number] = [2,3,4];
let arr:[number] = [2]; // 这个时候才是对的!
// 表示多种类型的数组,但是严格限制长度和类型必须对照
let arr:[string,number] = ['a',1];
// 报错:不能将类型“string”分配给类型“number”
// let arr:[string,number] = [1,'d'];
// any元组也需要规定元素数量
let arr:[any,any,any] = ['s',2,true];
其实[string,boolean]这种声明形式指的是元组,也就是一个已知元素数量和类型的数组
3.索引签名和工具类型Record的区别
其实Record工具类型的本质就是索引签名,不同之处只是用法,仅仅需要继承就可以了,不需要再写一遍 索引签名的用法
interface inf{
name:string;
age:number;
[k:string]:any;
}
let obj:inf = {
name:'yiye',
age:33,
city:'foshan'
}
Record工具类型的用法(ts内置的工具类型)
interface inf extends Record<string,any>{
name:string;
age:number;
}
let obj:inf = {
name:'yiye',
age:33,
city:'foshan'
}
Record工具类型的.d.ts声明文件源码是:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
所以用法就是继承这个工具类型,然后泛型参数1是属性类型,参数2是属性值的类型
4.interface和type的区别
如果在开发一个包或者要被继承,那么使用接口interface
如果要定义基础数据类型或者进行类型运算,那么使用类型别名type
不同点1:interface可以进行声明合并,type不可以
// 1.interface同名接口会自动进行声明合并
interface union{
name:string;
}
interface union{
age:number;
}
let u = {} as union;
// undefined
console.log(u.name);
// undefined
console.log(u.age);
// 但是使用其他属性,不会undefined,会报错:类型“union”上不存在属性“list”
console.log(u.list);
// 2.type类型别名不可以进行声明合并
// 报错:标识符“type_a”重复
// type type_a = number;
// type type_a = string;
不同点2:type可以直接进行赋值运算,而interface不可以,必须先继承
// 1.type可以进行类型运算(只能把type赋值给type,不能把type赋值给其他类型变量)
type type_a = number;
type type_sum = type_a | string;
// 2. interface不可以,必须要通过继承
interface inf_a{
name:string;
}
// “inf_a”仅表示类型,但在此处却作为值使用
// interface inf_a = inf_a;
// 正确做法是
interface inf_b extends inf_a{
age:number;
}
let inf = {} as inf_b;
// undefined undefined
console.log(inf.age,inf.name);
不同点3:interface只可以用于对象和函数;type则可以用于对象,函数,基础类型,数组,元组
// 1.接口
// 对象
interface obj{
name:string;
}
// 函数
interface func{
(x:string): number;
}
// 2.类型别名type
// 对象
type type_obj = {name:string};
// 函数
type type_func = (x:string) => string
// 基础类型
type type_boolean = true;
type type_null = null;
// 联合类型
type type_union = string | number;
// 数组
type type_arr = number[];
// 元组
type type_tuple = [number,string];
5.enum和const enum
enum可以进行反向查找,所以遍历得到的长度是预计长度的两倍
const enum不可以进行反向查找,所以得到的是预计长度
// 1. enum
enum REVERSE{
OK,
NO
}
// 0
console.log(REVERSE.OK)
// OK
console.log(REVERSE[0])
// OK
console.log(REVERSE[1])
// undefined,虽然是undefined,但是不会报错!
console.log(REVERSE[10])
// 遍历,得到枚举的值和反向查找的值
// of不可以,警告需要有[Symbol.iterator]方法
for(let item in REVERSE){
// 0 1 OK NO
console.log(item);
}
// 2. const enum
const enum ONE{
OK,
NO
}
console.log(ONE.OK)
// 报错:只有使用字符串文本才能访问常数枚举成员。
// console.log(ONE[0]);
// 遍历
// 报错:"const" 枚举仅可在属性、索引访问表达式、导入声明的右侧、导出分配或类型查询中使用。
/* for(let item in ONE){
} */
应用
1. 类型键入
type User = {
outer:string;
// 内部使用一个数组
innerList:{
innerName:string
}[]
}
// (property) outer: string
type userOut = User['outer'];
/* 属性数组
(property) innerList: {
innerName: string;
}[] */
type userList = User['innerList'];
// 类型键入,获取数组的一个项
// number表示数组子项的类型是number
type userListItem = userList[number];
let item:userListItem = {
innerName:'yiye'
}
// { innerName: 'yiye' }
console.log(item)
2 装饰器
function fun() {
return function(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(target); // 该装饰器所在的类或函数 any: 类
console.log(key); // 装饰器应用的变量名 string : getDecorator
console.log(descriptor); // 装饰应用的变量的descriptor属性
// {writable: true, enumerable: false, configurable: true, value: ƒun}
};
}
class A {
@fun()
getDecorator() {
console.log('测试');
}
}
let obj:A = new A();
obj.getDecorator();
3. typeof
typeof 关键字在 JS 中用来获取变量的类型,运算结果是一个字符串(值)。而在 TS 中表示的是推算一个变量的类型
// 1.1 typeof变量,得到的是变量的类型
let str_1 = 'hello'
// string
console.log(typeof str_1);
type type_1 = typeof str_1;
let obj_1:type_1 = 'dd';
// dd
console.log(obj_1)
// 1.2 typeof常量,得到的是常量的值
const str_2 = 'abc'
// 虽然打印得到的是string
console.log(typeof str_2);
// 但是通过type赋值为类型
type type_2 = typeof str_2;
// 此时会报错
// 报错:不能将类型“"typeof常量得到的类型是常量的值"”分配给类型“"abc"”
// let obj_2:type_2 = 'typeof常量得到的类型是常量的值';
// 这个时候才正确
let obj_3:type_2 = 'abc';
// 1.3 typeof对象
interface person{
name:string,
age:number
};
let obj:person = {
name:'yiye',
age:11
}
// object
console.log(typeof obj)
// 本质上就是:type type_obj = person
type type_obj=typeof obj;
// 1.4 typeof函数
function foo(key:string){
return key;
}
// type type_func = (key: string) => string
type type_func = typeof foo;
4.keyof
keyof关键字用来获取一个对象类型的所有key类型
type type_1 = {
id:number,
name:string
}
// keyof type_1得到 "id" | "name"
// 因为作为变量key_1的类型,所以key_1只能被赋值为"id" | "name"
let key_1: keyof type_1 = 'id'
// let key_1: keyof type_1 = 'name'
// 报错:不能将类型“"a"”分配给类型“"id" | "name"”
// let key_1: keyof type_1 = 'a'
console.log(key_1);
// keyof应用到泛型
// 表示传递的第一个值是对象,第二个值是对象的属性
function foo<T extends Object, K extends keyof T>(obj:T,key:K){
console.log(obj[key]);
}
interface key{
name:string,
age:number
}
let obj:key = {
name:'yiye',
age:11
}
// yiye
foo(obj,'name');
// 11
foo(obj,'age');
// 报错:类型“"a"”的参数不能赋给类型“"name" | "age"”的参数
// foo(obj,'a');
版权声明:本文为aleave原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。