Tabla de contenido
Combinar atributos básicos con el mismo nombre
Combinar atributos no básicos con el mismo nombre
Atributo de solo lectura (solo lectura)
Aserciones TS y protectores de tipo
afirmación de asignación segura
La diferencia entre tipo e interfaz.
Múltiples tipos de paso de parámetros
Parámetros predeterminados genéricos
¿Qué es TS?
TS : Abreviatura de TypeScript , es un lenguaje de programación gratuito y de código abierto desarrollado por Microsoft.
También puedes echar un vistazo a: Programación tipo TypeScript que no conoces
Tabla de contenido
Combinar atributos básicos con el mismo nombre
Combinar atributos no básicos con el mismo nombre
Atributo de solo lectura (solo lectura)
Aserciones TS y protectores de tipo
afirmación de asignación segura
La diferencia entre tipo e interfaz.
Múltiples tipos de paso de parámetros
Parámetros predeterminados genéricos
La relación entre TS y JS
Comparado con JS, TS es un superconjunto de JS En pocas palabras, JavaScript
agrega un sistema de tipo basado en , de modo que cada parámetro tenga un significado claro, lo que brinda indicaciones más inteligentes .
En términos relativos JS
, TS
es un lenguaje fuertemente tipado , por lo que para proyectos, hará que el código sea más estandarizado, resolviendo así la complejidad de los códigos de proyectos a gran escala.En segundo lugar, el navegador no lo reconoce, por lo que al compilar, TS
el TS
archivo primero Compilar para JS
archivar.
Instalar TS
Ejecutando una orden:
$ npm install -g typescript
//或
$ yarn global add typescript
ver versión
$ tsc -v
compilar
$ tsc test.ts
# test.ts => test.js
Compilar en línea
Para mayor comodidad, podemos usar un editor en línea: TypeScript Playground[1], así
imagen.png
Y también puede echar un vistazo a las ts
conversiones correspondientes generadas y los códigos posteriores ES5
, ES6
también hay ejemplos relacionados para que los vea.
Tipos de datos básicos de TS
Aquí, los tipos de datos de TS simplemente se clasifican de la siguiente manera:
-
Tipos básicos:
string
,number
,boolean
,symbol
,bigint
,null
,undefined
-
Tipos de referencia:
array
,Tuple
(tupla),object
(contieneObject
y{}
),function
-
Tipos especiales:
any
,unknow
,void
,nerver
,Enum
(enumeración) -
Otros tipos:
类型推理
,字面量类型
,交叉类型
type
Nota: y puede usarse en el caso interface
, que se explicará en detalle a continuación. Si hay más vagos, puede echar un vistazo primero.
tipo básico
//字符串
let str: string = "Domesy"
// 数字
let num: number = 7
//布尔
let bool: boolean = true
//symbol
let sym: symbol = Symbol();
//bigint
let big: bigint = 10n
//null
let nu: null = null
//undefined
let un: undefined = undefined
requiere atención:
-
null
yundefined
dos tipos, una vez asignados, no se pueden asignar a ningún otro tipo -
symbol
es único, asumiendo que está definiendo unosym1
, entonces sym === sym1 es falso
tipo de referencia
Formación
Dos caminos:
-
escriba el nombre + []
-
Matriz<tipo de datos>
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
let arr2: Array<number> = [1, 2, '3'] // error
//要想是数字类型或字符串类型,需要使用 |
let arr3: Array<number | string> = [1, 2, '3'] //ok
tupla (tupla)
Se puede decir que upleArray
es un caso especial de uple, por lo anterior arr3
podemos ver que su tipo puede ser string
o puede ser number
, pero no hay una restricción específica para cada elemento.
Entonces Tuple
el papel es limitar el tipo de elementos y limitar el número de matrices.Al mismo tiempo, Tuple
este valor de concepto existe TS
y JS
no existe en
Aquí hay un problema: en TS
, se permite aumentar Tuplepush
(es decir, permitir el uso de métodos), pero no se permite en acceso
let t: [number, string] = [1, '2'] // ok
let t1: [number, string] = [1, 3] // error
let t2: [number, string] = [1] // error
let t3: [number, string] = [1, '1', true] // error
let t5: [number, string] = [1, '2'] // ok
t.push(2)
console.log(t) // [1, '2', 2]
let a = t[0] // ok
let b = t[1] // ok
let c = t[2] // error
objeto
-
object
Para tipos no primitivos, es posible usar el objeto directamente en la definición, pero informará un error si desea cambiar las propiedades del objeto. La razón es que no hay restricciones en las propiedades internas específicas del objeto. , por lo que debe usar {} para definir el tipo interno
let obj1: object = { a: 1, b: 2}
obj1.a = 3 // error
let obj2: { a: number, b: number } = {a: 1, b: 2}
obj2.a = 3 // ok
Object
(O mayúscula), lo que significa que se pueden asignar todos los tipos primitivos o no primitivos, excepto null
`undefined
let obj: Object;
obj = 1; // ok
obj = "a"; // ok
obj = true; // ok
obj = {}; // ok
obj = Symbol() //ok
obj = 10n //ok
obj = null; // error
obj = undefined; // error
función
definir función
-
Hay dos formas, una es
function
y la otra es箭头函数
-
Al escribir, también puede escribir el tipo del valor de retorno. Si escribe, debe tener el valor de retorno del tipo correspondiente, pero generalmente se omite , porque
TS
la función de inferencia de tipo de la función puede inferir correctamente el tipo de valor de retorno.
function setName1(name: string) { //ok
console.log("hello", name);
}
setName1("Domesy"); // "hello", "Domesy"
function setName2(name: string):string { //error
console.log("hello", name);
}
setName2("Domesy");
function setName3(name: string):string { //error
console.log("hello", name);
return 1
}
setName3("Domesy");
function setName4(name: string): string { //ok
console.log("hello", name);
return name
}
setName4("Domesy"); // "hello", "Domesy"
//箭头函数与上述同理
const setName5 = (name:string) => console.log("hello", name);
setName5("Domesy") // "hello", "Domesy"
Tipo de parámetro
-
Parámetros opcionales: si la función necesita configurar parámetros opcionales, se puede realizar con ? , y los parámetros opcionales deben estar al final
-
Parámetros predeterminados: puede configurar los parámetros predeterminados en la función usted mismo, use = para lograr
-
Parámetros restantes: el operador de propagación todavía se puede usar ...
// 可选参数
const setInfo1 = (name: string, age?: number) => console.log(name, age)
setInfo1('Domesy') //"Domesy", undefined
setInfo1('Domesy', 7) //"Domesy", 7
// 默认参数
const setInfo2 = (name: string, age: number = 11) => console.log(name, age)
setInfo2('Domesy') //"Domesy", 11
setInfo2('Domesy', 7) //"Domesy", 7
// 剩余参数
const allCount = (...numbers: number[]) => console.log(`数字总和为:${numbers.reduce((val, item) => (val += item), 0)}`)
allCount(1, 2, 3) //"数字总和为:6"
sobrecarga de funciones
Sobrecarga de funciones : es la capacidad de crear múltiples métodos con el mismo nombre y diferente número o tipo de parámetros. En TypeScript, esto se representa proporcionando varias definiciones de tipo de función para la misma función. En pocas palabras: puede definir múltiples tipos de valores bajo la misma función y finalmente agregarlos
let obj: any = {};
function setInfo(val: string): void;
function setInfo(val: number): void;
function setInfo(val: boolean): void;
function setInfo(val: string | number | boolean): void {
if (typeof val === "string") {
obj.name = val;
} else {
obj.age = val;
}
}
setInfo("Domesy");
setInfo(7);
setInfo(true);
console.log(obj); // { name: 'Domesy', age: 7 }
tipo especial
cualquier
En TS, se puede atribuir cualquier tipo al any
tipo, por lo que any
el tipo se convierte en el tipo principal de todos los tipos . Al mismo tiempo, si no se especifica el tipo de la variable, se establecerá de forma predeterminada en cualquier tipo . Por supuesto, este tipo no es recomendable, porque pierde el TS el papel de
let d:any; //等价于 let d
d = '1';
d = 2;
d = true;
d = [1, 2, 3];
d = {}
desconocido
Al igual que any
con y, se puede usar como el tipo de nivel superior de todos los tipos , pero unknow
es más estricto , por lo que se puede decir que es any
el segundo tipo más grande, excepto por lo siguiente. A continuación, a modo de comparación any
, es principalmente estricto en los dos puntos siguientes:
Al mismo tiempo, podemos ver cómo se ve la traducción en ES5
enumeración numérica
tipo de inferencia
Después de haber aprendido estos tipos básicos, ¿tenemos que escribir de qué tipo es el campo para cada tipo? En realidad no, TS
si no establece el tipo y no asigna un valor, se deducirá como cualquier tipo, y si asigna un valor, se establecerá por defecto en el tipo.
-
unknow
Se comprobará el valor, peroany
no se comprobará el tipo. Para decirlo sin rodeos,any
el tipo se puede asignar a cualquier tipo, perounknow
solo alunknow
tipo yany
al tipo . -
unknow
Cualquier operación (como método, nuevo, etc.) no está permitida en el valor definido, pero cualquiera puedelet u:unknown; let a: any; u = '1'; //ok u = 2; //ok u = true; //ok u = [1, 2, 3]; //ok u = {}; //ok let value:any = u //ok let value1:any = a //ok let value2:unknown = u //ok let value3:unknown = a //ok let value4:string = u //error let value5:string = a //ok let value6:number = u //error let value7:number = a //ok let value8:boolean = u //error let value9:boolean = a //ok u.set() // error a.set() //ok u() // error a() //ok new u() // error new a() //ok
vacío
Cuando una función no tiene valor de retorno, TS predeterminará su valor de retorno para
void
escribirconst setInfo = ():void => {} // 等价于 const setInfo = () => {} const setInfo1 = ():void => { return '1' } // error const setInfo2 = ():void => { return 2 } // error const setInfo3 = ():void => { return true } // error const setInfo4 = ():void => { return } // ok const setInfo5 = ():void => { return undefined } //ok
nunca
Indica que una función nunca tendrá un valor de retorno, TS pensará que el tipo es
never
, luegovoid
, en comparación,never
debería servoid
un subconjunto, porquevoid
el valor de retorno real ni siquieraundefined
esnever
undefined
Las situaciones compatibles
never
son: cuando se lanza una excepción y un bucle infinitolet error = ():never => { // 等价约 let error = () => {} throw new Error("error"); }; let error1 = ():never => { while(true){} }
Enum (enumeración)
Las constantes con nombre se pueden definir para expresar la intención claramente o para crear un conjunto diferenciado de casos de uso
Aviso:
-
El tipo de una enumeración sólo puede ser
string
onumber
-
El nombre definido no puede ser una palabra clave
-
El tipo del grupo de enumeración es el tipo de número por defecto, y por defecto comienza a acumularse desde 0. Si se establece el valor por defecto , solo afectará a los siguientes valores
-
Al mismo tiempo, se admite el mapeo inverso (y el mapeo del valor del miembro al nombre del miembro) , pero no hay un valor predeterminado para el mapeo inteligente y solo puede estar delante del valor predeterminado
- editar
enumeración de cadenas
Tenga en cuenta que la enumeración de cadenas debe tener un valor predeterminado y no admite el mapeo inverso
enumeración constante
Además de
数字类型
y字符串类型
, existe un tipo especial, es decir, la enumeración constante , que seconst
define mediante goingenum
, pero este tipo no se compilará en ningúnJS
, solo se compilará el valor correspondienteenumeración heterogénea
Contiene una mezcla de
数字类型
y字符串类型
, por la misma razón que el mapeo inverso
let a; // 推断为any
let str = '小杜杜'; // 推断为string
let num = 13; // 推断为number
let flag = false; // 推断为boolean
str = true // error Type 'boolean' is not assignable to type 'string'.(2322)
num = 'Domesy' // error
flag = 7 // error
tipo literal
Tipo literal : En TS
, podemos especificar el tipo del parámetro, actualmente admite 字符串
, 数字
, 布尔
tres tipos. Por ejemplo, si defino str 的类型是 '小杜杜'
que el valor de str solo puede ser Xiaodudu
let str:'小杜杜'
let num: 1 | 2 | 3 = 1
let flag:true
str = '小杜杜' //ok
str = 'Donmesy' // error
num = 2 //ok
num = 7 // error
flag = true // ok
flag = false // error
Tipo de cruz (&)
Tipo de intersección : combine varios tipos en uno solo, use &
una conexión simbólica, como:
type AProps = { a: string }
type BProps = { b: number }
type allProps = AProps & BProps
const Info: allProps = {
a: '小杜杜',
b: 7
}
Combinar atributos básicos con el mismo nombre
Podemos ver 交叉类型
que combina los valores de atributo de dos atributos, por lo que ahora tenemos un problema, si ambos atributos tienen el mismo valor de atributo, qué pasará con el tipo total en este momento, primero observe el siguiente caso:
type AProps = { a: string, c: number }
type BProps = { b: number, c: string }
type allProps = AProps & BProps
const Info: allProps = {
a: '小杜杜',
b: 7,
c: 1, // error (property) c: never
c: 'Domesy', // error (property) c: never
}
Si es del mismo tipo y el tipo fusionado también es este tipo, ¿qué sucede si es un tipo diferente?
Nos unimos tanto en Aprops
como con diferentes tipos, uno es de tipo y el otro es de tipoBProps
c属性
c属性
number
string
¿Qué pasa con la combinación ahora allProps
?¿Puede ser uno c属性
o ambos, o solo uno de ellos number
? string
Sin embargo, en la práctica, c
pasar 数字类型
y 字符串类型
tampoco funcionará.Vemos un error, pero la realidad es que el tipo de c nunca es .
Esto se debe a que el c
atributo correspondiente es string & number
, pero obviamente este atributo no existe, por lo que c
el atributo esnever
Combinar atributos no básicos con el mismo nombre
interface A { a: number }
interface B { b: string }
interface C {
x: A
}
interface D {
x: B
}
type allProps = C & D
const Info: allProps = {
x: {
a: 7,
b: '小杜杜'
}
}
console.log(Info) // { x: { "a": 7, "b": "小杜杜" }}
Echemos un vistazo al caso: al mezclar varios tipos, si existe el mismo miembro y el tipo de miembro es un tipo de datos no básico, entonces la combinación puede ser exitosa.
Si b en la interfaz A también es del tipo número, se fusionará con el atributo básico del mismo nombre
clase (clase)
Presentó ES6
un class(类)
gadget llamado , no voy a hablar de la definición específica, creo que React
los amigos que lo han usado deben estar familiarizados con él.
método básico
Entre los métodos básicos están: 静态属性
, 静态方法
, 成员属性
, 成员方法
, 构造器
, get set方法
, veámoslos uno por uno:
Cabe señalar que: en el atributo de miembro, si no proporciona el valor predeterminado y si no lo usa, se informará un error. Si no desea informar un error, proporcione como ! , como:name4!:string
class Info {
//静态属性
static name1: string = 'Domesy'
//成员属性,实际上是通过public上进行修饰,只是省略了
nmae2:string = 'Hello' //ok
name3:string //error
name4!:string //ok 不设置默认值的时候必须加入 !
//构造方法
constructor(_name:string){
this.name4 = _name
}
//静态方法
static getName = () => {
return '我是静态方法'
}
//成员方法
getName4 = () => {
return `我是成员方法:${this.name4}`
}
//get 方法
get name5(){
return this.name4
}
//set 方法
set name5(name5){
this.name4 = name5
}
}
const setName = new Info('你好')
console.log(Info.name1) // "Domesy"
console.log(Info.getName()) // "我是静态方法"
console.log(setName.getName4()) // "我是成员方法:你好"
Veamos cómo se traduce el código anterior a ES5:
"use strict";
var Info = /** @class */ (function () {
//构造方法
function Info(_name) {
var _this = this;
//成员属性
this.nmae2 = 'Hello'; //ok
//成员方法
this.getName4 = function () {
return "\u6211\u662F\u6210\u5458\u65B9\u6CD5:".concat(_this.name4);
};
this.name4 = _name;
}
Object.defineProperty(Info.prototype, "name5", {
//get 方法
get: function () {
return this.name4;
},
//set 方法
set: function (name5) {
this.name4 = name5;
},
enumerable: false,
configurable: true
});
//静态属性
Info.name1 = 'Domesy';
//静态方法
Info.getName = function () {
return '我是静态方法';
};
return Info;
}());
var setName = new Info('你好');
console.log(Info.name1); // "Domesy"
console.log(Info.getName()); // "我是静态方法"
console.log(setName.getName4()); // "我是成员方法:你好"
campos privados (#)
Los campos privados de ECMACMAScript se admiten desde TS 3.8 .
Cabe señalar que, 私有字段
a diferencia de los campos regulares, las principales diferencias son:
-
Un campo privado
#
comienza con un carácter, también llamado nombre privado; -
Cada nombre de campo privado está calificado de forma única para la clase que lo contiene;
-
No puede usar modificadores de accesibilidad de TypeScript (como público o privado) en campos privados;
-
No se puede acceder a los campos privados fuera de la clase contenedora y ni siquiera se pueden detectar.
class Info { #name: string; //私有字段 getName: string; constructor(name: string) { this.#name = name; this.getName = name } setName() { return `我的名字是${this.#name}` } } let myName = new Info("Domesy"); console.log(myName.setName()) // "我的名字是Domesy" console.log(myName.getName) // ok "Domesy" console.log(myName.#name) // error // Property '#name' is not accessible outside class 'Info' // because it has a private identifier.(18013)
Atributo de solo lectura (solo lectura)
Propiedades de solo lectura : con
readonly
decoración, solo se pueden inicializar en el constructor , y en TS, solo las propiedades eninterface
, se pueden identificar comotype
class
readonly
-
readonly
Realmente solo está编译阶段
haciendo una revisión de código -
Las palabras modificadas
radonly
soloconstructor
se pueden modificar en etapas y no se permite modificarlas en otros momentos.class Info { public readonly name: string; // 只读属性 name1:string constructor(name: string) { this.name = name; this.name1 = name; } setName(name:string) { this.name = name // error this.name1 = name; // ok } }
Herencia (extiende)
Herencia : Es un punto más importante, lo que significa que el hijo puede heredar la idea del padre, es decir,
子类
después de la herencia父类
, tiene父类
los atributos y métodos, que esHOC
algo similar aAquí hay otro
super
campo, déjame contarte sobre él para aquellos que no saben, su función es llamar a las propiedades y métodos en la clase padre// 父类 class Person { name: string age: number constructor(name: string, age:number){ this.name = name this.age = age } getName(){ console.log(`我的姓名是:${this.name}`) return this.name } setName(name: string){ console.log(`设置姓名为:${name}`) this.name = name } } // 子类 class Child extends Person { tel: number constructor(name: string, age: number, tel:number){ super(name, age) this.tel = tel } getTel(){ console.log(`电话号码是${this.tel}`) return this.tel } } let res = new Child("Domesy", 7 , 123456) console.log(res) // Child {."name": "Domesy", "age": 7, "no": 1 } console.log(res.age) // 7 res.setName('小杜杜') // "设置姓名为:小杜杜" res.getName() // "我的姓名是:小杜杜" res.getTel() // "电话号码是123456"
modificador
Hay tres modificadores principales:
-
public : se puede llamar en cualquier lugar de la clase, en la subclase y fuera
-
protected : se puede llamar en cualquier lugar de la clase o subclase, pero no se puede llamar fuera
-
privado : se puede llamar en la clase y no se puede llamar en ningún lugar de la subclase o fuera
class Person { public name: string protected age: number private tel: number constructor(name: string, age:number, tel: number){ this.name = name this.age = age this.tel = tel } } class Child extends Person { constructor(name: string, age: number, tel: number) { super(name, age, tel); } getName(){ console.log(`我的名字叫${this.name},年龄是${this.age}`) // ok name 和 age可以 console.log(`电话是${this.tel}`) // error 报错 原因是 tel 拿不出来 } } const res = new Child('Domesy', 7, 123456) console.log(res.name) // ok Domesy console.log(res.age) // error console.log(res.tel) // error
abstracto
abstract : una clase declarada con la palabra clave abstract se denomina clase abstracta , y el método declarado se denomina método abstracto.
-
Clase abstracta : significa que no se puede instanciar porque contiene uno o más métodos abstractos.
-
Método abstracto : se refiere a un método que no contiene una implementación específica;
-
Nota: las clases abstractas no se pueden instanciar directamente, solo se pueden instanciar las subclases que implementan todos los métodos abstractos.
-
abstract class Person {
constructor(public name: string){}
// 抽象方法
abstract setAge(age: number) :void;
}
class Child extends Person {
constructor(name: string) {
super(name);
}
setAge(age: number): void {
console.log(`我的名字是${this.name},年龄是${age}`);
}
}
let res = new Person("小杜杜") //error
let res1 = new Child("小杜杜");
res1.setAge(7) // "我的名字是小杜杜,年龄是7"
anulando y sobrecargando
-
Anular : la subclase anula el método heredado de la clase principal
-
Sobrecarga : se refiere a proporcionar múltiples definiciones de tipo para la misma función, similar a la sobrecarga de las funciones anteriores.
// 重写 class Person{ setName(name: string){ return `我的名字叫${name}` } } class Child extends Person{ setName(name: string){ return `你的名字叫${name}` } } const yourName = new Child() console.log(yourName.setName('小杜杜')) // "你的名字叫小杜杜" // 重载 class Person1{ setNameAge(name: string):void; setNameAge(name: number):void; setNameAge(name:string | number){ if(typeof name === 'string'){ console.log(`我的名字是${name}`) }else{ console.log(`我的年龄是${name}`) } }; } const res = new Person1() res.setNameAge('小杜杜') // "我的名字是小杜杜" res.setNameAge(7) // "我的年龄是7"
tsconfig.json
tsconfig.json contiene configuraciones relacionadas con la compilación de TypeScript . Al cambiar los elementos de configuración de compilación, podemos hacer que TypeScript compile ES6, ES5 y códigos de nodo.
campo importante
files - 设置要编译的文件的名称; include - 设置需要进行编译的文件,支持路径模式匹配; exclude - 设置无需进行编译的文件,支持路径模式匹配; compilerOptions - 设置与编译流程相关的选项。
opción compilerOptions
{ "compilerOptions": { /* 基本选项 */ "target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT' "module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015' "lib": [], // 指定要包含在编译中的库文件 "allowJs": true, // 允许编译 javascript 文件 "checkJs": true, // 报告 javascript 文件中的错误 "jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react' "declaration": true, // 生成相应的 '.d.ts' 文件 "sourceMap": true, // 生成相应的 '.map' 文件 "outFile": "./", // 将输出文件合并为一个文件 "outDir": "./", // 指定输出目录 "rootDir": "./", // 用来控制输出目录结构 --outDir. "removeComments": true, // 删除编译后的所有的注释 "noEmit": true, // 不生成输出文件 "importHelpers": true, // 从 tslib 导入辅助工具函数 "isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似). /* 严格的类型检查选项 */ "strict": true, // 启用所有严格类型检查选项 "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错 "strictNullChecks": true, // 启用严格的 null 检查 "noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误 "alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict' /* 额外的检查 */ "noUnusedLocals": true, // 有未使用的变量时,抛出错误 "noUnusedParameters": true, // 有未使用的参数时,抛出错误 "noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误 "noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿) /* 模块解析选项 */ "moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6) "baseUrl": "./", // 用于解析非相对模块名称的基目录 "paths": {}, // 模块名到基于 baseUrl 的路径映射的列表 "rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容 "typeRoots": [], // 包含类型声明的文件列表 "types": [], // 需要包含的类型声明文件名列表 "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。 /* Source Map Options */ "sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置 "mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置 "inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件 "inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性 /* 其他选项 */ "experimentalDecorators": true, // 启用装饰器 "emitDecoratorMetadata": true // 为装饰器提供元数据的支持 } }
-
Aserciones TS y protectores de tipo
aserción TS
Se divide en tres tipos:
类型断言
,非空断言
,确定赋值断言
Cuando la aserción falla, se puede usar: doble aserción
tipo aserción
En un entorno específico, conoceremos el tipo específico de este valor mejor que TS, y no necesitamos que TS juzgue. El entendimiento simple es que la aserción de tipo le dirá al compilador que no necesita verificarlo. Créeme , es de este tipo.
Hay dos maneras:
-
Paréntesis angulares
-
como : recomendado
//尖括号 let num:any = '小杜杜' let res1: number = (<string>num).length; // React中会 error // as 语法 let str: any = 'Domesy'; let res: number = (str as string).length;
Pero debe tenerse en cuenta que la sintaxis del corchete angular informará un error en React , porque
JSX
entrará en conflicto con la sintaxis, por lo que solo puede usar la sintaxis asafirmación no nula
Se puede usar un nuevo operador de expresión de postfijo
!
para afirmar que los operandos no son nulos ni indefinidos en contextos donde el verificador de tipos no puede determinar el tipo.
imagen.pngES5
El código que comparamosPodemos ver que
!
nos puede ayudar a filtrarnull
yundefined
escribir, es decir, el compilador por defecto solo pasarástring
el tipo de datos, por lo que se puede asignar comostr1
Pero se eliminará
ES5
después de convertirse, por lo que cuando se transfiera , aún se reproducirá.!
null
null
afirmación de asignación segura
La aserción de asignación definitiva se introdujo en
TS
la versión 2.7, que permite colocar un número después del atributo de instancia y la declaración de variable!
para indicarTS
que el atributo se asignará definitivamente.let num: number; let num1!: number; const setNumber = () => num = 7 const setNumber1 = () => num1 = 7 setNumber() setNumber1() console.log(num) // error console.log(num1) // ok
doble afirmación
Después de que falla la aserción, se puede usar, pero generalmente no se usará
Caso de falla: el tipo subyacente no se puede afirmar como una interfaz
interface Info{ name: string; age: number; } const name = '小杜杜' as Info; // error, 原因是不能把 string 类型断言为 一个接口 const name1 = '小杜杜' as any as Info; //ok
tipo de guardia
Tipo de protección : una expresión que puede realizar comprobaciones en tiempo de ejecución para asegurarse de que el tipo está dentro de un rango determinado .
Mi sensación personal es que type guard significa que puede configurar varios tipos, pero prefiero a qué tipo se refiere
En la actualidad, hay cuatro guardias de tipos comunes: palabra clave in , palabra clave typeof , palabra clave interfaceof y predicado de tipo (es)
en palabra clave
Se utiliza para juzgar si este atributo está en ese
interface Info { name: string age: number } interface Info1{ name: string flage: true } const setInfo = (data: Info | Info1) => { if("age" in data){ console.log(`我的名字是:${data.name},年龄是:${data.age}`) } if("flage" in data){ console.log(`我的名字是:${data.name},性别是:${data.flage}`) } } setInfo({name: '小杜杜', age: 7}) // "我的名字是:小杜杜,年龄是:7" setInfo({name: '小杜杜', flage: true}) // "我的名字是:小杜杜,性别是:true"
tipo de palabra clave
Se utiliza para juzgar tipos básicos, como cadena | número, etc.
const setInfo = (data: number | string | undefined) => { if(typeof data === "string"){ console.log(`我的名字是:${data}`) } if(typeof data === "number"){ console.log(`我的年龄是:${data}`) } if(typeof data === "undefined"){ console.log(data) } } setInfo('小杜杜') // "我的名字是:小杜杜" setInfo(7) // "我的年龄是:7" setInfo(undefined) // undefined"
interfaz de palabra clave
Se usa para determinar si una instancia es un constructor o cuando se usa una clase
class Name { name: string = '小杜杜' } class Age extends Name{ age: number = 7 } const setInfo = (data: Name) => { if (data instanceof Age) { console.log(`我的年龄是${data.age}`); } else { console.log(`我的名字是${data.name}`); } } setInfo(new Name()) // "我的名字是小杜杜" setInfo(new Age()) // "我的年龄是7"
tipo predicado (es)
function isNumber(x: any): x is number { //默认传入的是number类型 return typeof x === "number"; } console.log(isNumber(7)) // true console.log(isNumber('7')) //false console.log(isNumber(true)) //false
la diferencia entre los dos
A través de la introducción anterior, podemos encontrar que el concepto de
断言
y类型守卫
es muy similar para determinar el tipo de parámetro, pero es断言
más autoritario.Le dice directamente al editor que el parámetro es de este tipo, y type guard es más como determinar de qué tipo es el parámetro. . (Entendimiento personal, si hay algo mal, indíquelo ~)alias de tipo, interfaces
alias de tipo (tipo)
alias de tipo : es decir
type
, se utiliza para dar un nuevo nombre a un tipotype InfoProps = string | number const setInfo = (data: InfoProps) => {}
interfaz
Interfaz : representa abstracciones de comportamiento en lenguajes orientados a objetos y también se puede utilizar para describir la forma de los objetos.
Use la palabra clave de interfaz para definir una interfaz
forma de objeto
La interfaz se puede utilizar para describir
对象
, incluyendo principalmente los siguientes datos:可读属性
,只读属性
,任意属性
-
Atributos legibles : cuando definimos una interfaz, es posible que nuestros atributos no necesiten ser todos, ¿esta es la necesidad ?
-
Atributo de solo lectura : el atributo modificado con solo lectura es un atributo de solo lectura, lo que significa que se puede definir y no se puede cambiar más adelante.
-
Atributo arbitrario : este atributo es extremadamente importante, se puede usar incluso si no está definido, como [datos: cadena]: cualquiera . Por ejemplo, si encapsulamos un componente, y el componente encapsulado no exporta el tipo correspondiente, pero queremos que no reporte un error, entonces podemos usar cualquier atributo
interface Props { a: string; b: number; c: boolean; d?: number; // 可选属性 readonly e: string; //只读属性 [f: string]: any //任意属性 } let res: Props = { a: '小杜杜', b: 7, c: true, e: 'Domesy', d: 1, // 有没有d都可以 h: 2 // 任意属性,之前为定义过h } let res.e = 'hi' // error, 原因是可读属性不允许更改
índice de firma
- Definición: las firmas de índice se utilizan para describir tipos que se "recuperan mediante indexación"
- Formato: como
[props: string]:any
- Escenario de aplicación: resolución de problemas de parámetros
export default {} interface IFullName { firstName: string lastName : string age?: number singName?: string [props: string]: any } // 注意点: 如果使用接口来限定了变量或者形参, 那么在给变量或者形参赋值的时候,多一个或者少一个都不行 // 实际开发中往往会出现多或者少的情况,怎么解决? // 少一个或者少多个属性 // 解决方案: 可选属性 let goddass1:IFullName = {firstName: "邱", lastName: "淑贞"}; let goddass2:IFullName = {firstName: "邱", lastName: "淑贞", age: 18}; // 多一个或者多多个属性 // 方案一:使用变量 let info = {firstName: "邱", lastName: "淑贞", age: 18, singName: "赌王", dance: "芭蕾"}; let goddass3:IFullName = info // 方案二: 使用类型断言 let goddass4:IFullName = ({firstName: "邱", lastName: "淑贞", age: 18, singName: "赌王", dance: "芭蕾"}) as IFullName; // 索引签名? // 索引签名用于描述那些“通过索引得到”的类型 // 注意点: 对象中的键,会被转化为字符串 interface Ibeauty { [props: string]: string } let name:Ibeauty = {name1: "邱淑贞", name2: "李嘉欣", name3: "周慧敏"}; interface Iage { [props: string]: number } let afe:Iage = {age1: 18, age2: 20}; // 方案三: 索引签名 let goddass5:IFullName = {firstName: "邱", lastName: "淑贞", age: 18, singName: "赌王", dance: "芭蕾"};
-
heredar
Herencia : al igual que las clases, las interfaces también tienen propiedades heredadas y
extends
campos de uso.interface nameProps { name: string } interface Props extends nameProps{ age: number } const res: Props = { name: '小杜杜', age: 7 }
interfaz de tipo de función
Al mismo tiempo, puede definir funciones y clases, agregar clases
new
modificadas y no agregar nuevas funcionesinterface Props { (data: number): number } const info: Props = (number:number) => number //可定义函数 // 定义函数 class A { name:string constructor(name: string){ this.name = name } } interface PropsClass{ new (name: string): A } const info1 = (fun: PropsClass, name: string) => new fun(name) const res = info1(A, "小杜杜") console.log(res.name) // "小杜杜"
La diferencia entre tipo e interfaz.
A través del estudio anterior, encontramos que
类型别名
y接口
son muy similares, se puede decir que en la mayoría de los casos,type
yinterface
son equivalentesSin embargo, en algunos escenarios específicos, la brecha sigue siendo relativamente grande. Veámoslos uno por uno.
tipo de datos básicos
-
type
yinterface
ambos pueden definir objetos y funciones -
type
Puede definir otros tipos de datos, como cadenas, números, tuplas, tipos de unión, etc., perointerface
notype A = string // 基本类型 type B = string | number // 联合类型 type C = [number, string] // 元祖 const dom = document.createElement("div"); // dom元素 type D = typeof dom
expandir
interface
Se puede extendertype
ytype
también se puede extender comointerface
, pero los dos implementan la extensión de diferentes maneras. -
interface
seextends
logra a través -
type
se&
logra a través// interface 扩展 interface interface A { a: string } interface B extends A { b: number } const obj:B = { a: `小杜杜`, b: 7 } // type 扩展 type type C = { a: string } type D = C & { b: number } const obj1:D = { a: `小杜杜`, b: 7 } // interface 扩展为 Type type E = { a: string } interface F extends E { b: number } const obj2:F = { a: `小杜杜`, b: 7 } // type 扩展为 interface interface G { a: string } type H = G & {b: number} const obj3:H = { a: `小杜杜`, b: 7 }
Definición duplicada
interface
se puede definir varias veces y se fusionará, perotype
nointerface A { a: string } interface A { b: number } const obj:A = { a: `小杜杜`, b: 7 } type B = { a: string } type B = { b: number } // error
Tipos de unión
Tipos de unión : indica que el valor puede ser uno de varios tipos. Cuando no se asigna ningún valor, solo se puede acceder a los atributos y métodos compartidos por los dos tipos en el tipo de unión, como:
const setInfo = (name: string | number) => {} setInfo('小杜杜') setInfo(7)
setInfo
Reciba uno de los anterioresname
, peroname
puede recibirstring
onumber
escribir, entonces este parámetro es un tipo conjuntoSindicato Discriminado
Unión discriminada : contiene tres características, a saber
可辨识
, ,联合类型
,类型守卫
,La esencia de este tipo es: un método de protección de tipos que combina tipos de unión y tipos literales .
Si un tipo es un tipo conjunto de varios tipos y varios tipos contienen un atributo común, este atributo común se puede usar para crear diferentes bloques de protección de tipos.
Es decir, los anteriores se usan juntos, aquí hay un pequeño ejemplo:
interface A { type: 1, name: string } interface B { type: 2 age: number } interface C { type: 3, sex: boolean } // const setInfo = (data: A | B | C) => { // return data.type // ok 原因是 A 、B、C 都有 type属性 // return data.age // error, 原因是没有判断具体是哪个类型,不能确定是A,还是B,或者是C // } const setInfo1 = (data: A | B | C) => { if (data.type === 1 ) { console.log(`我的名字是${data.name}`); } else if (data.type === 2 ){ console.log(`我的年龄是${data.age}`); } else if (data.type === 3 ){ console.log(`我的性别是${data.sex}`); } } setInfo1({type: 1, name: '小杜杜'}) // "我的名字是小杜杜" setInfo1({type: 2, age: 7}) // "我的年龄是7" setInfo1({type: 3, sex: true}) // "我的性别是true"
A
,B
y tres interfaces están definidasC
, pero las tres interfaces contienentype
atributos, de modotype
que可辨识的属性
, y otros atributos solo están relacionados con la interfaz de la función.Luego, a través de los atributos identificables
type
, se pueden usar sus atributos relacionadosgenérico
Genéricos : los genéricos se refieren a una característica que no especifica un tipo específico de antemano al definir una función, interfaz o clase, pero especifica el tipo al usarlo
En otras palabras, los genéricos son una plantilla que permite que la con. Comparadomisma función acepte diferentes tipos de parámetros
any
¿Por qué necesita genéricos?
Veamos primero un ejemplo:
const calcArray = (data:any):any[] => { let list = [] for(let i = 0; i < 3; i++){ list.push(data) } return list } console.log(calcArray('d')) // ["d", "d", "d"]
En el ejemplo anterior, encontramos que
calcArray
si se pasa cualquier tipo de parámetro, la matriz devuelta esany
del tipoComo no sabemos cuáles son los datos entrantes, los datos devueltos también son
any的数组
Pero el efecto que queremos ahora es: no importa qué tipo pasemos, se puede devolver el tipo correspondiente ¿Qué debemos hacer en este caso? Así que aquí
泛型
estásintaxis genérica
Primero modifiquemos el ejemplo anterior con genéricos,
const calcArray = <T,>(data:T):T[] => { let list:T[] = [] for(let i = 0; i < 3; i++){ list.push(data) } return list } const res:string[] = calcArray<string>('d') // ok const res1:number[] = calcArray<number>(7) // ok type Props = { name: string, age: number } const res3: Props[] = calcArray<Props>({name: '小杜杜', age: 7}) //ok
Después del caso anterior, encontramos que el entrante
字符串
,数字
,对象
, puede devolver el tipo correspondiente, para lograr nuestro objetivo, echemos un vistazo a continuación泛型语法
:function identity <T>(value:T) : T { return value }
Múltiples tipos de paso de parámetros
Tenemos múltiples marcadores de posición de tipo desconocido, podemos definir cualquier letra para representar diferentes tipos de parámetros
const calcArray = <T,U>(name:T, age:U): {name:T, age:U} => { const res: {name:T, age:U} = {name, age} return res } const res = calcArray<string, number>('小杜杜', 7) console.log(res) // {"name": "小杜杜", "age": 7}
interfaz genérica
Al definir interfaces, también podemos usar genéricos
interface A<T> { data: T } const Info: A<string> = {data: '1'} console.log(Info.data) // "1"
clase genérica
Los genéricos también pueden definir clases.
class clacArray<T>{ private arr: T[] = []; add(value: T) { this.arr.push(value) } getValue(): T { let res = this.arr[0]; console.log(this.arr) return res; } } const res = new clacArray() res.add(1) res.add(2) res.add(3) res.getValue() //[1, 2, 3] console.log(res.getValue) // 1
alias de tipo genérico
type Info<T> = { name?: T age?: T } const res:Info<string> = { name: '小杜杜'} const res1:Info<number> = { age: 7}
Parámetros predeterminados genéricos
El denominado parámetro predeterminado es el tipo especificado. Al igual que el valor predeterminado, cuando el tipo no se puede inferir del parámetro de valor real, este tipo predeterminado funcionará.
const calcArray = <T = string,>(data:T):T[] => { let list:T[] = [] for(let i = 0; i < 3; i++){ list.push(data) } return list }
Letras comunes genéricas
Use letras de uso común para indicar algunas representaciones variables:
-
T : significa Tipo , generalmente se usa como el primer nombre de variable de tipo al definir genéricos
-
K : significa Clave , que indica el tipo de clave en el objeto ;
-
V : significa Valor , indicando el tipo de valor en el objeto ;
-
E : significa Elemento , el tipo de elemento representado ;
habilidades comunes
Hay muchas palabras clave y tipos de herramientas en TS. Al usarlas, debe prestar atención a la aplicación de genéricos . A veces puede haber ciertos problemas en la combinación.
Se debe prestar especial atención a los tipos de herramientas extends
, typeof
, Partial
, Record
, Exclude
,Omit
extiende
extends : Comprobar si posee sus atributos, aquí por ejemplo conocemos 字符串
y 数组
poseemos length
atributos, pero number
no tenemos este atributo.
const calcArray = <T,>(data:T): number => {
return data.length // error
}
calcArray
La función de lo anterior es solo obtener data的数量
, pero en este momento TS
se reportará un error en .Esto se debe a que TS no está seguro si el atributo pasado tiene el atributo de longitud .Después de todo, cada atributo no puede ser exactamente igual
Entonces, ¿cómo resolverlo en este momento?
Ya hemos determinado que para obtener los datos pasados length
, es decir, el atributo pasado debe tener length
este atributo, si no, no se le permitirá llamar a este método.
En otras palabras, calcArray
es necesario tener la función de verificar atributos, para el ejemplo anterior es verificar si length
hay una función, es por eso que necesitamos el atributo de extends para ayudarnos a identificar:
interface Props {
length: number
}
const calcArray = <T extends Props,>(data:T): number => {
return data.length // error
}
calcArray('12') // ok
calcArray([1,3]) //ok
calcArray(2) //error
Se puede ver calcArray(2)
que se reportará un error porque number
el tipo no tiene length
esta propiedad
tipo de
palabra clave typeof : explicamos la función de typeof en la protección de tipos. Además, esta palabra clave también puede realizar la introducción de tipos , como se muestra en la figura a continuación, que puede inferir los tipos contenidos en Props
clave de
palabra clave keyof : puede obtener todos key
los valores de una interfaz de objeto y puede verificar si existe la clave en el objeto
interface Props {
name: string;
age: number;
sex: boolean
}
type PropsKey = keyof Props; //包含 name, age, sex
const res:PropsKey = 'name' // ok
const res1:PropsKey = 'tel' // error
// 泛型中的应用
const getInfo = <T, K extends keyof T>(data: T, key: K): T[K] => {
return data[key]
}
const info = {
name: '小张',
age: 7,
sex: true
}
getInfo(info, 'name'); //ok
getInfo(info, 'tel'); //error
operador de acceso al índice
Operador de acceso al índice : el acceso al índice se puede realizar a través del operador [] , y se puede acceder a una de las propiedades
en
en : tipo de mapeo, utilizado para mapear y atravesar tipos de enumeración
inferir
infer : se puede usar como una declaración condicional y se puede usar para infer
declarar una variable de tipo y usarla. como
type Info<T> = T extends { a: infer U; b: infer U } ? U : never;
type Props = Info<{ a: string; b: number }>; // Props类:string | number
type Props1 = Info<number> // Props类型:never
Parcial
Sintaxis parcial : Partial<T>
Función: ¿Hacer que todos los atributos sean opcionales ?
interface Props {
name: string,
age: number
}
const info: Props = {
name: '小王',
age: 7
}
const info1: Partial<Props> = {
name: '小徐'
}
Del código anterior, se requieren el nombre y la edad. Para información, se deben establecer los atributos de nombre y edad, pero para info1, siempre que sea un objeto, no es importante si hay atributos de nombre y edad.
Requerido
Sintaxis requerida : Required<T>
Función: hacer que todos los atributos sean obligatorios y Partial
lo contrario
interface Props {
name: string,
age: number,
sex?: boolean
}
const info: Props = {
name: '小王',
age: 7
}
const info1: Required<Props> = {
name: '小徐',
age: 7,
sex: true
}
Solo lectura
Sintaxis de solo lectura : Readonly<T>
Función: agregue el modificador de solo lectura a todos los atributos para lograr. Es decir, no se puede modificar.
interface Props {
name: string
age: number
}
let info: Readonly<Props> = {
name: '小徐',
age: 7
}
info.age = 1 //error read-only 只读属性
A juzgar por el código anterior, Readonly
después de la modificación, el atributo no se puede cambiar de nuevo, uso inteligente
Registro
Sintaxis de registro : Record<K extiende keyof any, T>
Función: Convierte K
los valores de todos los atributos del tipo en T
tipos.
interface Props {
name: string,
age: number
}
type InfoProps = 'JS' | 'TS'
const Info: Record<InfoProps, Props> = {
JS: {
name: '小徐',
age: 7
},
TS: {
name: 'TypeScript',
age: 11
}
}
A juzgar por el código anterior, InfoProps
las propiedades de las propiedades contienen respectivamente Props
las propiedades
Una cosa a tener en cuenta es: K extends keyof any
su tipo puede ser: string
, number
,symbol
Elegir
Sintaxis de selección : Pick<T, K extiende la clave de T>
Función: seleccione los subatributos de un determinado tipo y conviértalos en subtipos que contengan algunas propiedades de este tipo.
interface Props {
name: string,
age: number,
sex: boolean
}
type nameProps = Pick<Props, 'name' | 'age'>
const info: nameProps = {
name: '小徐',
age: 7
}
Del código anterior, Props
los atributos originales incluyen name
, age
y sex
tres atributos. Los seleccionamos a través de Pick, por lo que no sename
necesitan atributos .age
sex
Excluir
Excluir语法:Excluir<T, U>
Función: Elimina el tipo U en el tipo T.
// 数字类型
type numProps = Exclude<1 | 2 | 3, 1 | 2> // 3
type numProps1 = Exclude<1, 1 | 2> // nerver
type numProps2 = Exclude<1, 1> // nerver
type numProps3 = Exclude<1 | 2, 7> // 1 2
// 字符串类型
type info = "name" | "age" | "sex"
type info1 = "name" | "age"
type infoProps = Exclude<info, info1> // "sex"
// 类型
type typeProps = Exclude<string | number | (() => void), Function> // string | number
// 对象
type obj = { name: 1, sex: true }
type obj1 = { name: 1 }
type objProps = Exclude<obj, obj1> // nerver
Del código anterior, comparamos los tipos. Cuando hay U en T, se eliminará el atributo correspondiente. Si no hay ningún atributo en U en T, o T y U son exactamente iguales, volverá al nervio, y el objeto siempre regresanerver
Extra
Extra语法:Extra<T, U>
Función: Extrae U de los tipos a los que se puede asignar T. Contrario a Excluir
type numProps = Extract<1 | 2 | 3, 1 | 2> // 1 | 2
Omitir
Omitir sintaxis : Omitir <T, U>
Función: eliminar los atributos del tipo declarado para obtener un nuevo tipo
La diferencia con Excluir : Omitir devuelve un nuevo tipo, que se Exclude
basa en el principio, y Exclude
se devuelve según el tipo propio
no anulable
Sintaxis no anulable : rol: excluir y NonNullable<T>
de T null
undefined
Tipo de retorno
Sintaxis de tipo de retorno :ReturnType<T>
Función: Se utiliza para obtener el tipo de retorno de la función T.
type Props = ReturnType<() => string> // string
type Props1 = ReturnType<<T extends U, U extends number>() => T>; // number
type Props2 = ReturnType<any>; // any
type Props3 = ReturnType<never>; // any
Del código anterior, ReturnType puede aceptar cualquier tipo y nunca, porque estos dos tipos pertenecen al tipo de nivel superior y contienen funciones
Parámetros
Parámetros : Parameters<T>
Función: se utiliza para obtener el tipo de parámetro del tipo de función de adquisición.
type Props = Parameters<() => string> // []
type Props1 = Parameters<(data: string) => void> // [string]
type Props2 = Parameters<any>; // unknown[]
type Props3 = Parameters<never>; // never
Fin
referencia:
-
Mecanografiado 4.0[2]
-
Comprensión profunda de TypeScript[3]
-
Una guía de estudio rara de TS (palabras de 1.8W)[4]
y varios recursos en Internet.
resumen
En este punto, el TS
conocimiento relevante se ha terminado. Creo que tendrá TS
una comprensión más profunda después de dominar este conocimiento. Este artículo está clasificado de acuerdo con su propio entendimiento. Personalmente, creo que esta clasificación es más razonable. Si hay algo mejor Las sugerencias son bienvenidas para señalar en el área de comentarios ~
Cuando entré en contacto con él por primera vez TS
, me resistí un poco, pero a medida que pasaba el tiempo, descubrí que TS
es realmente fragante y TS
no es demasiado difícil. Siempre que pases una cierta cantidad de tiempo, combinando y proyectándote, encontrarás la ley de la verdadera fragancia.