JS和TS中有哪些数据类型
JS 的datatype
- null
- undefined
- string
- number
- boolean
- bigint
- symbol
- Object
- 包含了 Array,Function,Date...等
TS 的datatype
- 包含了JS的所有数据类型
- void
- never
- enum
- unknown
- any
- 自定义类型
- type
- interface
如何理解TS的数据类型?
JS的数据类型和TS的数据类型不一样,JS的数据类型指的是一个值的数据类型,TS的数据类型是从一个集合的角度去理解的
如下图所示:
图的上半部分:null undefined 1 2 3 a b c false 等等的每一个值它就是JS的数据类型。
图的下半部分:
1 | 1.1 | ... | 2 | 2.2 | ...
a | b | c | ...
所有的数字的集合,包括整数,小数,正负数等等,它称之为TS的number类型
所有字符串的集合,称之为 string 类型
等等...
所以得 从集合得角度理解TS的数据类型
如何在TS里描述对象的数据类型?
用索引签名或Record泛型来描述对象
type A = {
[k: string]: number
}
type A2 = Record<string, number>
type A3 = {
name: string
age: number
}
用 [] 或 Array泛型来描述数组对象
思考:下面的数组类型描述是可以的吗?
type A = Array
是不可以的,TS会报错告诉你,泛型类型“Array<T>”需要1个类型参数
所以数组的类型如何描述呢?
- 第一种
type A = string[]
const a:A = ['h', 'i']
type B = number[]
const b: B = [12, 34]
//========================
//下面的等价于上面的
type A = Array<string>
type B = Array<number>
- 第二种
type D = [string, string, string]
const noError: D = ['哈', '哈', '哈']
// 下面的error这个会报错,提示D类型有三个参数,你只有两个
const error: D = ['h', 'i']
type E = [string, number]
const e: E = ['小明', 100]
type F = [string[], number[]]
const f: F = [['柴', '米', '油', '盐'], [1, 2, 3]]
结论:由于 Array太不精确,所以TS开发者一般用 Array<?> 或 string[] 或 [string, number] 来描述数组
描述函数对象
type FnA = (a: number, b: number) => number
// 如果类型有return,那么函数必须有return
// 参数有没有无所谓,但不能超过类型定义的参数数量
const haha: FnA = () => {
return 1
}
// 调用的时候必须传和类型一样数量的形参
haha(1, 2)
问:那如果不想有返回值呢?
type FnA = (a: number, b: number) => void
const haha: FnA = (x) => {
}
问:那类型返回不写void,写undefined 行不行
答:不行,类型返回undefined,函数也要返回undefine
type FnA = (a: number, b: number) => undefined
const haha: FnA = (x) => {
return undefined
}
问: 上面用的都是箭头函数, 类型是箭头函数, 调用也是箭头函数。那如果我想用普通函数,调用this,要怎么用呢?
-
普通函数的调用
- 普通函数的类型,也是要用箭头函数的
- 现在,我想要有一个普通函数,并且调用函数的this
type Person = { name: string; age: number; sayHi: FnWithThis } type FnWithThis = (this: Person, age: number) => void const sayHi: FnWithThis = function(age) { console.log('hi ' + this.name) console.log('age', age) } const x: Person = { name: 'huang', age: 18, sayHi: sayHi } x.sayHi(12) sayHi.call(x, 12)
总结: 由于 Function 太不精确,所以 TS 开发者一般用 () => ? 来描述函数
描述其他对象
其它的对象就是什么类型加什么类型,大体就是自己试试,不行会有报错,很明确的说明为什么不行
const d: Date = new Date()
const r: RegExp = /ab+c/
const r2: RegExp = new RegExp('ab+c')
const m: Map<string, number> = new Map()
m.set('key', 123)
const wm: WeakMap<{name: string}, number> = new WeakMap()
const s: Set<number> = new Set()
s.add(123)
const ws: WeakSet<string[]> = new WeakSet()
enum 的用法
何时用enum
举个例子:如下图所示
这是一个todo的案例,后端返回一个 status 字段, status字段有 4个值。1是todo, 2是done, 3是archived, 4是deleted。映射到前端就 1是未完成, 2是已完成, 3是归档, 4是不做了
所以前端需要定义一个 status 变量, 这个变量的值只能是上面定义的 1,2,3,4
此时就能用 enum
enum A {
todo = 1,
done,
archived,
deleted
}
// deno 后面开始没有等于某个值是因为,这样写,下面的值就相当于每个排列下来都加1
// 下面的写法同上
// enum A {
// todo = 1,
// done = 2,
// archived = 3,
// deleted = 4
//}
let status: A = 1
status = A.todo
status = A.done
- 另一个就是在权限控制的时候,可以用enum
例如:
// 用二进制表示权限
enum Permission {
None = 0,
Read = 1 << 0, // 0001
Write = 1 << 1, //0010
Delete = 1 << 2, // 0100
Manage = Read | Write | Delete, // 0111
}
type user = {
permission: Permission;
};
const user1: user = {
permission: 0b0001,
};
if ((user1.permission & Permission.Write) === Permission.Write) {
console.log('有写的权限');
}
if ((user1.permission & Permission.Manage) === Permission.Manage) {
console.log('有管理权限');
}
总结:平时除了这两种情况下,其他大多数情况下是不需要用到enum的
何时用enum会显得很呆
例如:
enum Fruit {
apple = 'apple',
banana = 'banana',
orange = 'orange
}
let f = Fruit.apple
f = Fruit.orange
console.log(f)
既然值是字符串,那为什么不写成下面这样子呢?
type Fruit = 'apple' | 'banana' | 'orange'
let f: Fruit = 'apple'
f = 'orange'
console.log(f)
什么是Type, 何时用Type
type:类型别名 (Type Aliases)
作用:给其他类型取个名字
type Name = string
type FalseLike = '' | 0 | false | null | undefined
type Point = { x: number; y: number }
type Points = Point[]
type Line = [Point, Point]
type Circle = { center: Point; radius: number }
type Fn = (a: number, b: number) => number
type FnWithProps = {
(a: number, b: number): number,
prop1: number
}
自己写的程序大多时候都可以用Type(对内,自己用的)。要是写插件让别人用的,那就不建议用Type
问: 别名是什么意思?
看下面例子:
type x = string
type Y = X
上面的例子中Y是什么?
答案是Y 是string, 为什么不是X呢,X就是一个别名,把string 赋给了Y
什么是interface, 何时用interfacce
interface: 声明接口
作用: 描述对象的属性
interface Data {
[k: string]: string
}
interface Point {
x: number;
y: number;
}
interface Points extends Array<Point>{}
interface Fn {
(x: number, y: number): number;
}
interface Data2 extends Data {}
type 和 interface 的区别
-
区别1
- interface是用来描述对象的
- type则描述所有数据
如下图:
-
区别2
-
type只是别名
-
interface则是类型声明
interface A { n: string } type B = A问: B是什么?难道跟type中的例子一样? 答案: B = A , 因为A是真实存在的类型,type只是类型别名,不是真实存在的
-
-
区别3
- Type不能重新赋值
type D = string D = number // 这是错误的上面的例子中D = number是错误的,type是不能重新赋值的
- interface可以自动合并
interface A { n: string; } interface A { z: number } let B:A = { n: 'a', z: 1 }interface的全局扩展,所有可以通过interface对类型进行扩展
declare global { interface String { aaa(x: string): void } } const s = 'string' s.aaa('bbb')对外API 尽量用 interface ,方便扩展 对内API 尽量用 type, 防止代码分散