【TS基础】个人学习记录2-认识数据类型,约束变量

数据类型

主要分为原始数据类型和对象类型,原始类型有7个,stringnumberbigintsymbolbooleannullundefined。这些都是最底层实现的类型,叫原始类型是因为对这些类型的变量做操作,不会影响原始值,操作结果通常以返回的方式获取。

对象类型有,arraytupleenum

数据类型的声明

首先知道 ,TS变量的声明往往要通过后置语法:注解变量类型,这种就是显式声明变量:

let num: number = 1;
// 当然也可以和js一样写,ts会自己推导上下文来判断----类型推论(但并不是万能的)
let num = 1;
// 也可以注解多个类型
let num: number | undefined

TS在编译成JS的时候,会有静态类型检测。编译器就会通过类型注解去检测变量类型,不一致就会报出编译期错误。

注意,如果使用内置构造函数去创建变量类型,TS是会报错的,例如:

let str: string = new String('2') // 得到的是个object不符合设定的string所以报错

原始类型

string

// 字符串字面量
let str: string = 'wow' 
// 显示类型转换
let str: string = String('wow') 
// 模板字符串
let str: string = `wow` 

number

let num: number = 6;
let num: number = Number(42);
let num: number = 3.14; /** 十进制浮点数 */
let num: number = 0b1010; /** 二进制整数 转成js会被转回十进制*/
let num: number = 0o744; /** 八进制整数 转成js会被转回十进制*/
let num: number = 0xf00d; /** 十六进制整数 转成js保持不变*/
let num: number = NaN;
let num: number = Infinity;

为啥二进制和八进制编译到es5回被转回十进制,我猜是因为二进制和八进制是es6的写法,es5本身不支持,所以会被转化。

bigint

number 表示的最大整数为 2^53 - 1,如果超过了这个界限,可以用 bigInt来表示,它可以表示任意大的整数,并且和number是不相等的,也就是不能一起运算和使用number的方法。

let bigNum: bigint = 9007199254740991n // 在一个整数字面量后加 n 的方式定义
const bigNum: bigint = BigInt(9007199254740991)

这个就先知道这么多就好,细节看

boolean

let bol: boolean = true;
let bol: boolean = new Boolean(1);

symbol

这个是es6新增的,表示值时唯一的。

let sym1: symbol = Symbol();
let sym2: symbol = Symbol('42');
let sym3: symbol = Symbol('42');
console.log(sym2 === sym3) // false

注意没有new Symbol()这种方式的创建方法, es6新增的取消了这种方式。

怎么用看

null和undefined

let nothing: null = null; // 好傻
let unde: undefined = undefined; //有点傻

undefined 和 null 是所有类型的子类型,可以赋值给其他类型的变量:

let num: number = undefined;
let u: undefined;
let num: number = u;

对象类型

array

需要指定子元素的类型(注意是非常严格的哦,比如往数字数组里push字符串编译会报错的):

/** 指定子元素是数字类型的数组 */
let num1: number[] = [1, 2, 3];
/** 指定子元素是字符串类型的数组 */
let num2: string[] = ['x', 'y', 'z'];

还可以用泛型定义数组类型,未来再学泛型。

/** 指定子元素是数字类型的数组 */
let num1: Array<number> = [1, 2, 3];
/** 指定子元素是字符串类型的数组 */
let num2: Array<string> = ['x', 'y', 'z'];

推荐第一种声明方式,能避免于JSX语法冲突,也能减少代码量。

之后还可以用接口表示数组用类表示数组

其实还有很多类数组,例如入参集合arguments,dom集合HTMLCollection等,他们有自己的api,不能和array混用。

tuple

这个是元组类型,最重要的特性就是可以限制数组元素的个数和类型。

let tuple: [string, number, boolean] = ["a", 2, false]; // 右侧类型写错或少赋值都会报错
let tuple: [string, number?, boolean?] = ["a"]; // 元素类型后缀一个 ? 来说明元素是可选的,可选元素必须在必选元素的后面,也就是如果一个元素后缀了 ?号,其后的所有元素都要后缀 ?号。

如果强行push元素的话,必须是[]里已注解的类型,但不能访问会报错,所以这样的操作不推荐。

元祖类型的使用可看这里的第四标题,基本上和数组类似。

enum

枚举类型,感觉就像是键值对的字典,每个键值对可以叫为一个枚举项

enum Flag { success = 1, error = -1 } 
enum Days = {sun, mon, tue, wed} // 不写=值的话,就默认等于索引值(像下标一样)
// 然后声明一个变量去拿里面的值,是枚举类型
let flag1: Flag = Flag.success // 1
let Days1: Days = Days.sun // 0
// 也可以直接拿取
console.log(Flag.success) // 1
console.log(Days[0]) // 0

特别的情况:

enum wow {a=3, b=2, c, d, e}
let A: wow = wow.a // 0
let B: wow = wow.b // 2
let C: wow = wow.c // 3 这个默认的索引值就为上一个值为开始算起+1,就算b为1.5也是加1成2.5
console.log(wow[3]) // 打印wow的值为3的居然打印出'c',是因为后者把前者a覆盖了

枚举项值如果不是数字就没有自动推导加1了,所以需要把每个枚举项都赋值了。

正向映射:就是正常的wow.a查找。

方向映射:就是通过值去找key,wow[3]。注意的是值为字符串枚举成员不会生成反向映射。

常数项:就是上面例子中的枚举项的样子。

计算所得项:就是枚举项中值是个计算语句,例如a='wow'.length

常数项和计算所得项的完整定义还是最好去看官方文档。

常数枚举:这种定义方式在编译后就会被删除,只留下枚举取出来的结果,能够减少转译后的es5代码量。且不能有计算所得项。

const enum Directions {  // 通过const来定义
    Up,
    Down,
    Left,
    // Right = 'right'.length 加这个直接报错
}

可以试着加和不加const转译一下结果。

外部枚举declare 定义的类型只会用于编译时的检查,编译后会被删除。

declare enum Directions {
    Up,
    Down,
    Left,
    Right
}
// 也可以
declare const enum Directions {...}

枚举合并:重复声明和两个对象合并一样。

enum Months {
  Jan = 1,
  Feb,
  Mar,
  Apr
}
enum Months {
  May = 5,
  Jun
}
console.log(Months.Apr) // 4
console.log(Months.Jun) // 6

枚举在项目中就用普通枚举就行了,方便运行时打印出来

object

表示非原始类型:

let obj: object

// 枚举类型
enum TokenType {
  ACCESS = 'accessToken',
  REFRESH = 'refreshToken'
}

obj = TokenType
obj = [1, 2, 3]
obj = [1, 'string'] // 元组类型
obj = { a: 1 }
obj = ()=> {}

可以看到枚举、数组、元组、返回空的函数和普通对象都是 object 类型,这种特性会引起一些问题,例如:

function Fn(obj: object) {
 let obj1 = {...object} // ts会报错说obj1可能是一个{},这是因为obj1 = {...()=> {}}就是一个空对象
 ...
}

// 可以这样限制成真正的对象类型
function Fn(obj: { [key: string]: unknown }) {
 let obj1 = {...object} 
 ...
}

其他

any

任意类型,能绕过静态类型检测。

不好的地方是,你去获取any变量上不存在的属性和方法是不会报错的:

let anything: any = {};
anything.doAnything(); // 不会提示错误
anything = 'x'; // 不会提示错误
let num: number = anything; // 不会提示错误

除此之外,几乎其他非常规操作也不会报错。

再对比之前的array声明,我们可以这样定义就能和es5的数组一样了

let arr: any[] = ['1', 2, true]

变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:

let something; // 等同于let something: any;
something = 'seven';
something = 7;

any类型身上的任意子孙属性也都是any类型,会通过调用链传递类型。

当引入缺少类型注解的第三方库或者正在把JS应用改造成TS应用的时候,可以先把变量全部注解为any类型。平时在全TS的项目中开发的时候,要避免使用any类型,还要禁用隐式any。

nuknown

用来描述类型不确定的变量,可以被赋值任意类型的变量,但自己只能赋值给unknown和any类型。

let value: unknown
// value = true   OK
// value = 10   OK
...
let value1: unknown = value   // OK
let value2: any = value       // OK
let value3: boolean = value   // Error
...

它就像个严格版的any类型,例如:

function fn(obj: any) { // 可以传入任何类型
	console.log(obj.name) // 不会提示错误
}

function fn(obj: unknown) { // 可以传入任何类型
	console.log(obj.name) // 会提示错误
}

所以,只有当unknown被确定了类型后,才能使用相应类型的方法和属性,否者会报错。例如可以这样使用:

let result: unknown;
if (typeof result === 'number') {
  result.toFixed(); // 此处 hover result 提示类型是 number,不会提示错误
}

前面说到过,unknown只能赋值给unknown和any类型,可能不是很理解在应用中是起什么作用的,举个例子:

function fn(obj: unknown) { 
	console.log(obj) 
    return obj
}

let obj: object = {}
obj = fn(obj) // 因为函数返回的是个unknown类型,所以会报错说不能将unknown赋予到object类型的变量上

void

就是表示没有返回值的函数,也可以说是表示没有返回任何类型。void和undefined之间有个怪异设计,这里就先不记录了。

function Fn():void{
	console.log('fn')
}
// 如果是有返回类型的
function Fn():number{
	return 123;
}

never

表示永远不会发生值的类型,never 是所有类型的子类型,它可以给所有类型赋值。

例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式;

function error(message: string): never {
    throw new Error(message);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值