ts问题小总结

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 ObjectK 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');

在这里插入图片描述

在 Vue 项目中使用 TypeScript,可以通过配置 TSLint 来进行代码规范和类型检查。以下是一些设置 TSLint 的经验总结: 1. 安装依赖 ``` npm install --save-dev tslint tslint-config-prettier tslint-plugin-prettier tslint-eslint-rules typescript ``` 2. 配置 TSLint 在项目根目录下创建 tslint.json 文件,并添加以下内容: ``` { "extends": [ "tslint:recommended", "tslint-config-prettier" ], "rules": { "interface-name": false, "no-console": false, "no-empty": false, "no-unused-expression": false, "no-unused-variable": false, "semicolon": [true, "always"] }, "linterOptions": { "exclude": [ "node_modules/**", "dist/**" ] } } ``` 以上配置文件的含义: - extends:继承的规则,包含了 TSLint 推荐的规则和 Prettier 的规则。 - rules:自定义的规则,可以根据团队的需求进行配置。 - linterOptions:指定需要忽略的文件或目录。 3. 配置 VS Code 在 VS Code 中安装以下插件: - TSLint - Prettier - Code formatter 然后在项目根目录下创建 .prettierrc 文件,并添加以下内容: ``` { "singleQuote": true, "trailingComma": "es5", "semi": true, "tabWidth": 2 } ``` 最后,在 VS Code 的设置中添加以下配置: ``` { "editor.formatOnSave": true, "vetur.validation.template": false, "prettier.eslintIntegration": true, "eslint.validate": [ "javascript", "javascriptreact", "vue", "typescript" ], "typescript.validate.enable": false, "tslint.enable": true } ``` 以上配置的含义: - editor.formatOnSave:在保存时自动格式化代码。 - vetur.validation.template:禁止 Vetur 对模板的验证,因为它可能与 TSLint 发生冲突。 - prettier.eslintIntegration:启用 Prettier 和 ESLint 的集成。 - eslint.validate:指定需要验证的文件类型。 - typescript.validate.enable:禁止 VS Code 内置的 TypeScript 验证器,因为它可能与 TSLint 发生冲突。 - tslint.enable:启用 TSLint 验证器。 4. 迁移经验 如果是一个已经存在的 Vue 项目,需要将 JavaScript 代码迁移到 TypeScript,可以按照以下步骤进行: - 安装 TypeScript 和 @types/node - 将 .js 文件改名为 .ts 文件,并修改文件中的代码 - 在 Vue 组件中添加 <script lang="ts"> 标签,并将代码移到其中 - 逐步修改代码,添加类型注解和接口定义 需要注意的是,迁移过程中可能会遇到一些问题,例如: - 无法识别某些模块,需要在 tsconfig.json 中配置 paths - 需要安装额外的类型声明文件,例如 @types/vue、@types/lodash 等 - 一些 JavaScript 的语法不支持 TypeScript,需要进行调整 总之,迁移过程需要耐心和谨慎,可以先从一些简单的模块开始,逐步迁移。同时,使用 TSLint 和 VS Code 可以帮助我们更方便地进行代码规范和类型检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值