TypeScript学习笔记之数据类型

布尔值:

let flag:boolean=true/false;

数字:

let num:number=3;

字符串:

let s:string="me"/'me'/`me`;

可以用双引号(" ")或者单引号(' ')表示字符串,同时还可以使用模板字符串(` `)。

模板字符串可以定义单行或者多行,可以通过${expr}这种方式嵌入表达式,推荐这种方式

let name:string=`xx`;
let my:string=`我的名字是${name}`;
console.log(my);
//输出:我的名字是xx

但是这时name报错,错误号:TS2451: Cannot redeclare block-scoped variable 'name',只有短短三句语句,居然就出了个错。想来想去,想到了window,在其他页面打印window,果然window上定义了name属性,的确是重复定义了。知道了原因,就好办了。一个方法是稍微改一下变量名;还有一个方法是将脚本封装到模块(module)内。

数组:

两种定义方式:

  1. 在元素类型后面接上[]
    let arr:number[]=[1,2,3,4];
    console.log(arr);
    //输出:(4) [1, 2, 3, 4]
  2. 使用数组泛型Array<元素类型>
    let arr1:Array<number>=[1,2,3,4];
    console.log(arr1);
    //输出:(4) [1, 2, 3, 4]

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

元组:

元组就是一个已知元素数量和类型的数组,且各元素的类型不必相同,但是赋值的类型与定义的类型必须一致。

let arr2:[number,string,number]=[1,'2',3];
console.log(arr2);
//输出:(3) [1, "2", 3]

当访问一个越界的元素,会使用联合类型替代。

arr2[3]='2';
console.log(arr2[3]);
//输出:2
//编译报错:TS2322:Type '2' is not assignable to type undefined

枚举:

枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。

enum Week {Sun,Mon,Tues,Wen,Thur,Fri,Sat}
let index0:Week=Week.Sun;
let sun:string=Week[0];
console.log(index0,sun);
//输出:0 "Sun"

一般情况下,从0开始为元素编号。当然,我们也可以手动的设置数值。由下面代码可以看出,当我们设置为从1开始的时候,后面的项是会累加的

enum Week1 {Sun=1,Mon,Tues,Wen,Thur,Fri,Sat}
console.log(Week1.Sun,Week1.Mon,Week1.Tues);
//输出:1 2 3

当然我们可以手动设置数值,但是一定要慎重,不然就会出现下面的情况哟。

enum Week1 {Sun,Mon,Tues=0,Wen,Thur,Fri,Sat}
console.log(Week1.Sun,Week1.Mon,Week1.Tues);
//输出:0 1 0
let day:string=Week1[0];
console.log(day);
//输出:Tues

枚举项也可以是计算所得项,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错。

enum Week2 {Sun='sun'.length,Mon,Tues,Wen,Thur,Fri,Sat}
//编译报错:TS1061:Enum members must have initializers
/*
* 正确使用方式:
*/
enum Week2 {Sun,Mon,Tues,Wen,Thur,Fri,Sat= "sat".length}
let day1:Week2=Week2.Sat;
let sat:string=Week[6];
console.log(day1,sat);
//输出:3 "Sat"

常数枚举,它会在编译阶段被删除,并且不能包含计算成员

/*
*  常数枚举会在编译阶段被删除,一直不明白啥意思,直到看见js文件
*/
枚举:
enum Week2 {Sun,Mon,Tues,Wen,Thur,Fri,Sat= "sat".length}
//编译后js
var Week2;
(function (Week2) {
    Week2[Week2["Sun"] = 0] = "Sun";
    Week2[Week2["Mon"] = 1] = "Mon";
    Week2[Week2["Tues"] = 2] = "Tues";
    Week2[Week2["Wen"] = 3] = "Wen";
    Week2[Week2["Thur"] = 4] = "Thur";
    Week2[Week2["Fri"] = 5] = "Fri";
    Week2[Week2["Sat"] = "sat".length] = "Sat";
})(Week2 || (Week2 = {}));
常数枚举:
const enum Directions {Up,Down,Left,Right}
//编译后js:
//无相关内容
//增加一条语句后:
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
//编译后js:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
//输出:(4) [0, 1, 2, 3]
/*
*  常数枚举,不能包含计算所得项成员
*/
const enum Directions {Up,Down,Left,Right="Right".length}
//编译报错:TS2474 const enum member initializers can only contain literal values and other computed enum values.

Any:

当你不清楚变量是什么类型,或者是来自于动态内容(用户输入或第三方库),总之是当你不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查时可以使用any来标记。总之就是啥类型都可以。

let n:any=undefined;
console.log(n);
//输出:undefined

在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。Any可以访问任何属性也可以调用任何的方法。它与object的区别是:object类型变量只是允许你给他赋任意值,但是不能够在它上面调用任意的方法。

let num1:any=4;
num1.toFixed(); //通过
let num2:object=2;
num2.toFixed(); //报错:TS2339
console.log(num1,num2);
//输出:4 2

变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。

Void

某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你会见到其返回值类型是 void

function f():void {
    alert('aaa');
}

一般来说声明一个void变量没什么用,因为他只可以被赋值为null或者undefined

Null和Undefined

null和undefined是所有类型的子类型

let num:number=undefined;
console.log(num);
//输出:undefined

然而,在指定了--strictNullChecks标记后,null和undefined只能赋值给void和他们自己本身,这能避免很多问题,因此官方鼓励使用这个标记。当你在某处想要传入string或null或undefined时,可以使用联合类型。

Never

表示那些永不存在的值得类型,是任何类型的子类型,也可以赋值给任何类型,但是除了never本身外任何一个类型都不可以给他赋值,any也不可以。

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

Object

非原始类型,也就是除了原始类型意外的类型,包括{},[],function

使用object类型,就可以更好的使用object的API,比如create

create({ prop: 0 }); // 通过
create(null); // 通过
create([1,2,3]); //通过
create(function a() {
    console.log(a);
}); //通过
create(42);//报错,TS2345: Argument of type '42' is not assignable to parameter of type 'object'.
let sym1 = Symbol();
create(sym1); //报错,TS2345: Argument of type 'symbol' is not assignable to parameter of type 'object'.
create("string"); //报错,TS2345: Argument of type '"string"' is not assignable to parameter of type 'object'.
create(false); //Error:(21, 8) TS2345: Argument of type 'false' is not assignable to parameter of type 'object'.

值得注意的是,在TS3.3.3333版本(我使用的版本)中undefined与null类型一样通过了编译,但在文档中却是不通过的

create(undefined);//通过

Symbols

ES6定义的新的原生类型,通过Symbol构造函数创建的,Symbols是不可改变且唯一的

let sym1=Symbol();
console.log(sym1); //Symbol()
let sym2=Symbol('x');
console.log(sym2);//Symbol(x)
let sym3=Symbol('x');
console.log(sym2==sym3);//false

Symbol也可以被用做对象的key值,但是在TS编译的时候报错了。即使不影响输出,但依然不明白为什么。如果您有答案欢迎下方评论,谢谢。

let sym=Symbol();
let obj={
    [sym]:'x'
};
console.log(obj[sym]);
//输出:x
但是,编译obj[sym]报错:TS2538: Type 'symbol' cannot be used as an index type.

Symbol也可以与计算属性的声明相结合,来声明对象的属性和类成员

const  computed=Symbol();
class C {
    [computed](){
        return 'sym';
    }
}
let c=new C();
let compute=c[computed]();
console.log(compute);
//输出:sym

内置Symbol,用来表示语言内部的行为。

  • Symbol.hasInstance属性,指向一个内部方法。当其他对象使用 instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)
    /*
    * 下面代码:MyClass是一个类,new MyClass()会返回一个实例。该实例的Symbol.hasInstance方法,
    * 会在进行instanceof运算时自动调用,判断左侧的运算或者表达式是否为Array的实例。
    */
    class MyClass {
        [Symbol.hasInstance](foo) {
            return foo instanceof Array;
        }
    }
    let m:any=new MyClass();
    console.log([1,2,3] instanceof m); 
    // 输出:true
  • Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Arrary.prototype.concat()时,是否可以展开。

    /*
    * 数组的默认行为是可以展开的,属性默认等于undefined,当该属性等于true时,也可以展开。
    */
    let arr=['c','d'];
    console.log(['a','b'].concat(arr,'e'));
    //输出:(5) ["a", "b", "c", "d", "e"]
    console.log(arr[Symbol.isConcatSpreadable]);
    //输出:undefined
    /*
    * 当属性为false时:
    */
    let arr1=['c','d'];
    arr1[Symbol.isConcatSpreadable]=false;
    console.log(['a','b'].concat(arr1,'e'));
    //输出:(4) ["a", "b", Array(2), "e"]==['a', 'b', ['c','d'], 'e']
    //          0: "a"
    //          1: "b"
    //          2: (2) ["c", "d", Symbol(Symbol.isConcatSpreadable): false]
    //          3: "e"
    //          length: 4
    //          __proto__: Array(0)
    类数组默认不展开,他的属性设为true,才可以展开
    let obj:any = {length: 2, 0: 'c', 1: 'd'};
    console.log(['a', 'b'].concat(obj, 'e'));
     //输出:  ["a", "b", {…}, "e"]
    //         0: "a"
    //         1: "b"
    //         2: {0: "c", 1: "d", length: 2, Symbol(Symbol.isConcatSpreadable): true}
    //         3: "e"
    //         length: 4
    __proto__: Array(0)
    obj[Symbol.isConcatSpreadable] = true;
    console.log(['a', 'b'].concat(obj, 'e')); 
    //输出:['a', 'b', 'c', 'd', 'e']
  • Symbol.iterator方法,被for-of语句调用。返回对象的默认迭代器。

  • Symbol.match方法,被String.prototype.match调用。正则表达式用来匹配字符串。

  • Symbol.replace方法,被String.prototype.replace调用。正则表达式用来替换字符串中匹配的子串。

  • Symbol.search方法,被String.prototype.search调用。正则表达式返回被匹配部分在字符串中的索引。

  • Symbol.species函数值,为一个构造函数。用来创建派生对象。

  • Symbol.split方法,被String.prototype.split调用。正则表达式来用分割字符串。

  • Symbol.toPrimitive方法,被ToPrimitive抽象操作调用。把对象转换为相应的原始值。

  • Symbol.toStringTag方法,被内置方法Object.prototype.toString调用。返回创建对象时默认的字符串描述。

  • Symbol.unscopables对象,它自己拥有的属性会被with作用域排除在外。

类型断言

简单地说就是你很确定、肯定以及100%的相信值得类型。类型断言好比其他语言的类型转换。但是不进行特殊的数据检查和解构,只在编译阶段起作用,没有运行时的影响。

两种形式:除了在TS里使用JSX时,只能使用as语法断言,其他情况两者自行选择

尖括号法

let s=<string>"sa";
console.log(s);//输出:sa

as语法

let s="sa" as string;
console.log(s);//输出:sa

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值