ts数据类型:
整理自ts系列
boolean
let bool:boolean = true;
string
let str:string = "string";
number
let num:number = 0;
array
let numbers:number[] = [1,2,3,4,5];
// number|string代表联合类型, 下面的高级类型中会讲
let numbers:(number|string)[] = [1,2,3,4,'5'];
// 通过泛型表示, Array<元素类型>
let numbers:Array<number> = [1,2,3,4,5];
元组(Tuple)
// 元组类型,表示一个已知元素数量和类型的数组, 各元素的类型可以不同:
let list1:[number, string] = [1, '2', 3]; // 错误, 数量不对, 元组中只声明有2个元素
let list2:[number, string] = [1, 2]; // 错误, 第二个元素类型不对, 应该是字符串'2'
let list3:[number, string] = ['1', 2]; // 错误, 2个元素的类型颠倒了
let list4:[number, string] = [1, '2']; // 正确
enum
any
undefined
所有类型的子类型
let str:undefined = "string"
null
所有类型的子类型
let num:null = 123
void
void的意义和any相反, 表示不是任何类型, 一般出现在函数中, 用来标记函数没有返回值:
function abc(n:number):void{
console.log(n);
}
never
never表示不可达,主要使用在`throw`的情况下:
function error():never{
throw '错了!';
}
其中,object包含:enum array tuple
接口(interface)
一种定义复杂类型的格式, 比如我们用对象格式存储一篇文章, 那么就可以用接口定义文章的类型:
interface Article {
title: string;
count: number;
content:string;
fromSite: string;
}
const article: Article = {
title: '为vue3学点typescript(2), 类型',
count: 9999,
content: 'xxx...',
fromSite: 'baidu.com'
}
通过基础类型组合而来的, 我们可以叫他高级类型. 包含: 交叉类型 / 联合类型 / 接口等等
用接口定义函数
接口不仅可以定义对象, 还可以定义函数:
// 声明接口
interface Core {
(n:number, s:string):[number,string]
}
// 声明函数遵循接口定义
const core:Core = (a,b)=>{
return [a,b];
}
类型别名(type)
类型别名可以表示很多接口表示不了的类型, 比如字面量类型(常用来校验取值范围):
type A = 'top'|'right'|'bottom'|'left'; // 表示值可能是其中的任意一个
type B = 1|2|3;
type C = '红'|'绿'|'黄';
type D = 150;
let a:A = 'none'; // 错误, A类型中没有'none'
更多组合
interface A1{
a:number;
}
type B = A1 | {b:string};
type C = A1 & {b:string};
// 与泛型组合
type D<T> = A1 | T[];
命名空间(namespace)
如果你发现自己写的功能(函数/类/接口等...)越来越多, 你想对他们进行分组管理就可以用命名空间, 比如"类":
namespace Tools {
const TIMEOUT:number = 100;
export class Ftp {
construtor() {
setTimeout(() => {
console.log("test")
}, TIMEOUT)
}
}
export function parseURL() {
console.log("parseURL")
}
}
export 是表示外部可以访问
Tools.TIMEOUT // error Tools上没有这个属性
Tools.parseURL() // parseURL
常用的就是用namesapce管理类型
namespace Food {
export type A = "蔬菜“ | ”水果" | "海鲜"
export interface Fruits {
taste: string,
price: number,
}
export interface Meat {
taste: string,
price: number,
}
}
let classif: Food.A
let fruits: Food.Fruits
引入写好的命名空间
方法一:
< reference path="./xxx.ts">
方法二:
import {xxx} from "xxx.ts"
声明(declare)
全局声明要以文件d.ts结尾
// global.d.ts
declare let s: string
declare interface Food {
(taste: string) : string
}
// app.ts
s = "sweet"
Food(s)
模块声明
// module.ts
declare module interface Meat {
(taste: string): void
}
// app.ts
const meat = require("./module.ts")
meat.Meat = ("salty") => console.log("salty")
交叉类型(&)
交叉类型是将多个类型合并为一个类型, 表示"并且"的关系,用&连接多个类型, 常用于对象合并:
interface A {a:number};
interface B {b:string};
const a:A = {a:1};
const b:B = {b:'1'};
const ab:A&B = {...a,...b};
联合类型(|)
联合类型也是将多个类型合并为一个类型, 表示"或"的关系,用|连接多个类型:
function setWidth(el: HTMLElement, width: string | number) {
el.style.width = 'number' === typeof width ? `${width}px` : width;
}
"泛型变量"和"泛型"
变量的概念我们都知道, 可以表示任意数据, 泛型变量也一样, 可以表示任意类型:
// 在函数名后面用"<>"声明一个泛型变量
function convert<T>(input:T):T{
return input;
}
在类名后面通过"<>"声明一个泛型变量, 类的方法和属性都可以用这个泛型, 接下来我们使用下泛型类:
let a = new Person<string>('詹姆斯邦德');
a.say(007) // 错误, 会提示参数应该是个string
a.say('007') // 正确
泛型类型
我们可以用泛型变量去描述一个类型(类型范围), ts的数组类型Array本身就是一个泛型类型, 他需要传递具体的类型才能变的精准:
let arr : Array<number>;
arr = ['123']; // 错误, 提示数组中只可以有number类型
arr = [123];
泛型接口
通过传入不同的类型参数, 让属性更灵活:
interface Goods<T>{
id:number;
title: string;
size: T;
}
let apple:Goods<string> = {id:1,title: '苹果', size: 'large'};
let shoes:Goods<number> = {id:1,title: '苹果', size: 43};
泛型约束
function echo<T>(input: T): T {
console.log(input.name); // 报错, T上不确定是否由name属性
return input;
}
T可以代表任意类型, 但对应的都是基础类型, 所以当我们操作input.name的时候就需要标记input上有name属性, 这样就相当于我们缩小了泛型变量的范围, 对泛型进行了约束:
// 现在T是个有name属性的类型
function echo<T extends {name:string}>(input: T): T {
console.log(input.name); // 正确
return input;
}
自动类型推断(不用你标类型了,ts自己猜)
ts会根据定义赋值自动判断类型,还会根据浏览器自带的api,比如typeof / instanceof自动做类推断
类型断言(你告诉ts是什么类型, 他都信)
有些情况下系统没办法自动推断出正确的类型, 就需要我们标记下, 断言有2种语法, 一种是通过" <> ", 一种通过"as", 举例说明:
let obj = 0.5 < Math.random() ? 1 : [1]; // number|number[]
// 断言, 告诉ts, obj为数组
(<number[]>obj).push(1);
//等价
(obj as number[]).push(1);
索引类型(keyof)
js中的Object.keys()和ts中keyof类似,用来获取ts对象类型中的key值
type A = keyof {a:1,b:'123'} // 'a'|'b'
type B = keyof [1,2] // '0'|'1'|'push'... , 获取到内容的同时, 还得到了Array原型上的方法和属性(实战中暂时没遇到这种需求, 了解即可)
type类型可以获得键值,也可以获得对象类型的值
type A = {a: 1, b: "123"}
type B = A['a']
let b:B = 2 // error b只能等于1
映射类型
映射类型就是修改类型的函数工具方法
Partial< T>就是让所有属性变成可选的
interface A = {
a: string,
b: number,
}
// {a?: string, b?: number}
interface A1 = Partial<A>
Required< T>让所有属性变成必选
type A = { a?: string, b?: string }
type A1 = Required<A> // {a: string, b: string}
Pick< T,K> 保留自己选择的属性,K表示想要保留的属性键值(是键值key!!)
type A = {a: number, b: string, c: boolean}
type A1 = Pick<A, 'a'|'b'> // {a: number, b: string}
Omit< T> 排除已选的属性
type A = {a: string, b: number}
type A1 = Omit<A, 'a'> // {b: number}
Record< K,T> 创建一个类型,K是key的类型,T是值的类型
type A = Record<string, number> // {[key: string]: number}
Exclude< T,U> 将T类型中,有和U类型相同的类型过滤掉
type A1 = Exclude<number|string, string|number[]> // number
// 兼容
type A2 = Exclude<number|string, any|number[]> // never , 因为any兼容number, 所以number被过滤掉
Extract< T,U> 提取T和U中相同的类型
type A1 = Extract<number|string, string|number[]> // string
Parameters 获取函数参数类型
interface fun = {
(a: number, b: string): string|number
}
type A = Parameters<fun> // [number, string]
extends 条件类型
Z extends T ? X : Y
如果Z的类型是T,那么就是返回X,否则返回Y
type A = string extends '123' ? string : '123' // '123'
type b = '123' extends string ? string : '123' // string