TypeScript(v3.1)

目录

 

基础类型

变量声明

接口、类型、函数

泛型

类型推断等

模块&命名空间


typescript的核心就是类型检查,类型的定义、类型的使用、给变量赋值之类的;typescript的基础建立在javascript,typescript需要经过编译,将typescript文件编译成javascript文件,真正用于运行在项目中也是javascript文件,但是因为平时用的JavaScript是弱类型语言比较容易出bug,所以typescript的出现可以稍微避免这样的问题以让项目使用更健全的代码;其他的结构、代码、变量声明、语法跟javascript一样;只是编译器在使用了不符合类型约束的字段时会报错之类的等事情;

**自言自语

联合类型、严格的泛型、类型推断、类型扩展(如 var test = null在非严格空检测下,可扩展为any类型、否则为null类型、null是test的为一值)、交叉类型、本地类型声明、泛型别名、用户定义的类型收窄模式(使用 is ,作为对typeof 和instanceof的补充)、类型参数的约束、不可及代码(发生在return、throw、break、continue等语句之后)、隐式返回、case语句贯穿、在模块中扩充全局或模块作用域、null和undefined类型(在严格空检测中,null和undefined不再是任何类型的有效值,而是它们自身类型或any类型的有效值)、非空断言操作符e!.name相当于if(e!=null){e.name}、抽象类的定义以及继承抽象类;--noUnusedParameters、--noUnusedLocals标记未使用的声明;关键词extends、keyof和查找类型、有条件类型、unique symbol、分布式有条件类型、有条件类型中的类型推断与关键字'infer',infer会引入一个带推断的类型以及在使用该类型时才知道具体的类型是什么、同一类型变量的多个候选类型在协变位置上(返回类型上)会被推断为联合类型,在抗变位置上(参数类型上)会被推断为交叉类型、预定义的有条件类型Exclude<T, U>,Extract<T, U>,ReturnType<T>,NonNullable<T>,InstanceType(T)、交叉类型上的keyof、识别命名空间、带元组类型的剩余参数、带有元组类型的展开表达式、类型断言(value as type, <type>value);

typescript支持与JavaScript几乎相同的数据类型,typescript还提供enum、unknown,在typescript文件中还可以自定义类型、简单的、复杂一点的,但都是由基础类型开始构建的自定义类型以及泛型语法的使用、interface、class等的使用、以及typescript的预定义类型的使用;typescript支持javascript几乎相同的声明关键字var、let、const、static;

基础类型

1,基础类型:number、string、boolean、数组(Array)、元组Tuple([])、枚举(enum Color{})、null、undefined、never、unknown、any、void;这些类型都比较容易理解;

number:数字类型,浮动数、十六进制字面量、八进制以及二进制字面量;

//一般在typescript声明变量,声明关键字如let、var、const、static(这个一般应在类class中),
//以及变量,以及变量的类型,以及赋值
//形如 var <abc>:type = value; 或用let关键字 let <abc>:type = value;定义块级变量;
//或用 const定义常量const <abc>:type = value;
//不同于 let、var这两个可以先不用赋值,const需要在定义时就赋值;
let num1: number = 6;
let num2: number = 0x15;
let num3: number = 0o7;
let num4: number = 0b10;
//在typescript的配置tsconfig.json中,属性strictNullChecks默认是false,
//所以 以上定义的变量当赋值为undefined或null时不会报错,即num1 = undefined;
//当一般不要这么做,若需要可以赋值undefined或null的话,
//使用联合类型即 let num1: number|defined | null;
//在严格空检测的情况,为类型不包含undefined的变量赋值undefined或null为报错,
//后面要讲到的类型也是如此;

***以下都假设在严格空检测的环境下;

boolean:布尔值为false/true;let bl = true;

string: 字符串类型,跟javascript一样,使用单引号、双引号,还可以是模板字符串;

//模板字符串可在字符串中间换行;
let str1: string = 'stringsss';
let str2: string = "stringsss";
let str3: string = `hello, it is a ${str2} yo`; 
//变量str3 相当于 'hello, it is a stringsss yo'

undefined:undefined类型的变量只能赋值undefined或any类型的值或void函数的返回值;

//
let und: undefined = undefined;
let und = void(0);
let und = void('str');
let und = <any>2; //类型断言,将类型为number的数据转为any类型;

null: 只能给类型为null的变量赋值为为null或any类型的数据;

//
let nulVar: null;
nulVar = null;
nulVar = <any> 2; //nulVar = 2 as any也是一样的;在JSX环境下需要用as;
//一般情况下,应该不需要这样;
//这句编译成javascript的话是 nulVar = 2;

void: 表示没有任何类型;一般用在没有返回值的函数中,作为没有返回值的函数的返回类型;所以没有返回值的函数的返回值、以及undefined(毕竟没有返回值的函数默认返回undefined)、以及void函数(估计void函数就是表示没有返回值的函数的意思)的返回值;

//
let voidVar: void;
voidVar = void(0);
voidVar = undefined;
function fn(): void{
    //不返回任何值;或者返回undefined;
    //除了undefined可以返回之外,返回其他类型会报错;
    
    //return undefined;
};

any: 与void相反,表示可以是任何类型;被定义为any的变量,只有在运行时根据值的类型推断才能知道具体的类型,所以在不知道具体类型时,可用any;

//any与Object的区别;
//any可以根据值推断变量此时的类型,而Object不可以;
//比如
let test: any = [2,3];
test.length; //不会报错;

let test2: Object = [2,3];
test2.length; //报错:Property 'length' does not exist on type 'Object';
test2.hasOwnProperty('test') //Okay

//any 类型的数据的使用;
let anyVar: any = 3;
let num: number = anyVar;
let anyArr: any[] = [true, 2, undefined,'str',null];

unknown:是版本3.0新加一个类型,unknown类型的值在没有类型断言或基于控制流的类型细化时不能unknown不能赋值给其他类型,除了赋值给它自己类型的和any类型的;同时unknown类型没有细化到确切类型前是不允许在其上进行任何操作的比如属性访问等;

//unknown 与 其他类型的交叉;
type t1 = unknown & string; //string;
type t2 = unknown & number; //number;
type t3 = unknown & null; // null;
type t4 = unknown & undefined & null; //never; (undefined & null is never)
type t5 = unknown & any; //any;
type t6 = unknown & string[]; //string[];
//....
//unknown 与 其他类型的联合
type t7 = unknown | string;//unknown;
type t8 = unknown | any; //any;
type t9 = unknown | string[]; //unknown;
type t10 = unknown | never;//unknown;
//这是因为几乎所有类型都能赋值给unknown;
//unknown在类型断言或用控制流细化类型前不能将unknown赋值给其他类型、
//也不可以在其上进行任何操作
function test(x: unknown): number{
    let a:number;
    a = unknown; //Error; 不能赋值
    x.toFixed(2);//Error; 不能在其上操作;
    x.hasOwnProperty('c'); //Error;
    return a;
}
//使用类型断言、基于控制流的类型细化;
function test(x: unknown): number{
	let a: number;
	a = <number>x; //类型断言;
    if(typeof x === 'number'){
        x.toFixed(2); //Ok; (number).toFixed(num)返回带有num个小数位的浮点数;
    }
    if(typeof x === 'function'){
        x.bind({}); //OK
    }
    return a;
}
test('string'); //OK
//估计是因为type'{}'相当于object,
//除了undefined、null、never、unknown之外的类型都可以赋给object类型;
keyof unknown; //never;
keyof any; //number, string, symbols;
type t11 = {[P in keyof unknown]: string};//等同于 type t11= {};
let obj: t11 = {}; //OK
obj1 = [2, 4]; //OK
obj1 = {hello: 'test'};//OK
obj1 = 3; //OK;
obj1 = undefined; //Error;
//需要这种形式的对象{} 或 {propperty: 'value', ...}
type t12 = {[x: string]: unknown};
let obj: t12 = {}; //OK
obj2 = {hello: 'test'};//OK
obj2 = [2, 4]; //Error; type 't12'不是数字索引签名;就是type u = {[x: number]: number}
obj2 = 3; //Error;

never:表示用不存在的值的类型,也表示程序没有可到达的终点;never是任何类型的子类型,never可以赋值给任何类型,但其他类型不能赋值给never类型;

//
function test1(): never{
    throw new Error('tt'); //
}

function test2():never{
    while(true){} //程序没有可到达的终点;
}

function test3():never{
    return test1(); //一个返回never类型的函数 的返回值;
}

数组:Array,typescript还有ReadonlyArray(顾名思义,只读数组);

//数组Array(形如Array<type> 或 type[]):如 
let arr : Array<string> = ['string']; //同 
let arr: string[] = ['string']; 
//如果元素的类型不确定的,可以 
//let arr:any[] = [2, true, 'str', 555];

let readonlyArr : ReadonlyArray<string> = ['str', 'hello'];
readonlyArr[0] = 'test'; //Error, 因为readonlyArr的元素只读;
let ha = readonlyArr as Array<string>;
ha[0] = 'test';//OK,用类型断言将只读转为Array<string>类型;

元组Tuple(形如[type1, type2, type3, ...] ):元组是元素个数和元素的类型是确定(即使定义为any之类的,也且这么认为)的数组;

let tuples: [any] = [4, true, '444']; //Error; 元组的个数是确定的,此处是1;
let tuples1:[number, string, undefined] = [3, 'rr', undefined];//Ok
tuples1.length;//OK, 

枚举enum:使用enum定义枚举类型 如 enum Color{Red, Green, Blue};或者enum Color{Red='red', 'Green'='green', Blue='clue'};;定义一个类型为枚举类型的变量let red: Color = Color.Red;或者 let green: Color=Color.Green; 枚举变量名习惯首字母大写;

//使用enum可以定义一系列带名字的常量;typescript支持基于数字或字符串的枚举;
//基于数字的枚举;枚举默认使用数字0作为第一个枚举变量的值,之后变量的值依次加1;如下:
enum EnumList {
    Enum1, //相当于Enum1 = 0,
    Enum2, //相当于Enum2 = 1,
    Enum3  //相当于Enum3 = 2
}
//也可以在定义时手动给值;如下:当一个枚举变量的值是数字且给定后,
//之后的变量若没有指定值,会默认在前一个变量的值增加1;
enum CityNo {
    Guangzhou = 1,
    Shenzhen = 2,
    Shanwei = 5,
    Dongguan // 相当于Dongguan = 6
}
//基于字符串的枚举;
enum CityAlias {
    Beijing = 'B',
    Shanghai = 'H',
    Tianjin = 'T'
}
//可以混用,即异构枚举
enum Test{
    Fly, //相当于Fly=0,
    Swim = 'Swimsuit',
    Run, //没有赋值
    'Dance'//相当于Dance = 'Dance',但又有些不一样;体现在编译后js代码
           //Test[Test[Dance] = void 0] = 'Dance', 后者是Test['Dance'] = 'Dance'
}
//数字枚举与字符串枚举的区别
//1,基于数字的枚举,其他枚举变量可以通过访问枚举变量知道其值,
//也可以通过编号反向映射得到枚举变量;
console.log(EnumList.Enum1); //0
console.log(Enum[0]); // 'Enum1'
//2,基于字符串的枚举没有编号一说,所以不能通过编号得到其变量名;
console.log(CityAlias.Beijing); //'B',
console.log(CityAlias['B']); //undefined,没法用CityAlias['B']得到'Beijing'

没有指定类型的变量,一般其类型是any,但是在noImplicitAny的环境下,不会被指定为any类型,只有在运行才会被确定是哪种类型;比如let gh; 未被赋值前使用,会被当做是undefined类型,所以let num: number=gh会报错说type 'undefined'  is not assignable to type 'number';非 noImplicitAny的环境下会是any类型,let num: number = gh不会报错,因为此时gh的类型是any;

Object、Number、String、Boolean也可以作为类型,但是一般不做这么做,对于Object会使用更具体的类型如Array、{}、class等或者object({}),对于Number、String、Boolean建议使用其对应的原始类型number、string、boolean;

let num: number = new Number(6); 
//Error; type 'Number' is not assignable to type 'number'
let num1: Number = 6;//OK
//其他类似;

变量声明

2,变量声明;typescript支持javascript几乎所有的声明关键字;var、let、const、函数声明等,typescript基本支持ES6的新语法;

接口、类型、函数

3,接口、类、函数、枚举;计算属性不支持联合类型、不支持可选属性;

接口:interface,可以用来表示一个对象应满足哪些要求(约束数据结构的类型),也就是interface可以用来表示类型; interface的属性可以是可选、可以是只读、可以是用索引签名定义的属性,其属性可以是任意可用的类型,interface也可以对对象方法约束;interface还可以作为函数签名,用来作为约束函数的定义和使用,只是此时interface的定义有点不同(interface Inter{  (a: number, c: string) => void}),也就是interface既可以定义约束对象的类型,也可以定义约束函数,另外可以作为类class的接口;interface约束数据结构其实也不就是特别严谨,使用的‘鸭子辩型法’或‘结构性子类型化’;在接口中使用索引签名需要注意:索引签名参数的类型要么是'number',要么是'string';

//***不要把以下代码放一起执行,不然会发生类型合并以及若有冲突会报错;
//比如第一个interface的定义age和第二个interface中的age有冲突,因为一个必须,另一个是可选;
//一段一段地执行;
//作为对象的约束
//约束一个对象必须有age和name属性,且不能有其他属性;
//且age属性的值的类型是number,name的是string;
interface Person{
    age: number,
    name: string
}
let person1 : Person={age: 5,name: 'test'};//OK
let person11: Person = {name: 'test'};//Error, name在Person中有定义,
                                //但{age: 5}中缺少属性name赋值;
//interface对对象的约束可以不那么严格,可以使用"?"让属性称为可选属性;
interface Person{
    age?: number,
    name: string
}
let person2: Person = {age: 5, name: 'test'};//Ok
let person21: Person = {name: 'test'}; //OK
//interface可以选择使用字符串索引签名,这样可以允许对象有任意个属性;
//如下,aga和name是明确的属性,age可选,name是必须的,另外可以有其他任意个任意类型的属性;
interface Person{
    age?: number,
    name: string,
    [index: string]: any
}
let person3: Person = {name: 'Test', birth: '2020-01-01', hobby: ['cry']};//OK
let person31: Person = {name: 'Test'};//OK
//所以可以使用索引签名允许一个拥有任意属性的数据结构;定义可索引类型,此时Person是个可索引类型;
interface Person{
    [index: string]: any,
}
let person4: Person = {};//OK
let Person41: Person = {halo: [5, 6, 'string']};//OK
let Person42: Person =  {halo: true};//Ok;因为Person中没有布尔值类型的属性;
let person43: Person = [true, 5, 'str']; //因为数组地索引也可以字符串如person43['0'];
//使用数字索引签名约束数组的数据结构;
interface Person{
    [index: number]: any;
}
let person5:Person = [true, 4, 'str']; //
let person51:Person = {hello: 'test'};//Error,
                                      //property 'hello' does not exist to type Person
let person52: Person = {}; //OK;
//interface也可以作为一个函数约束,及作为一个函数类型;
interface FnType{
    (a: string, b: number):void; //调用签名;
    age: number;
}
function test(){
}
test.age = 8;
let fn1: FnType = test; //OK, 签名个数可以少于定义的签名个数;参数类型逐个检查,要求类型是兼容
                        //返回值类型没有给,会根据返回值推断类型;
fn1('str', 6);
let val: FnType = {age: 4}; //Error; Type'{ age: number; }' provides no match 
            //for the signature '(a: string, b: number):void'.
//只读属性;只读属性只在赋值时可执行,但是在修改其值时会报错;
interface Person{
    readonly firstName: string;
}
let person7: Person = {firstName: 'Cai'};//OK
person7.firstName = 'Li'; //Error, Property 'firstName' is readonly;
//注意****
interface Person {
    readonly firstName?: string; //此时 firstName的类型会被推断为 'string | undefined'
}

//当出现同名的interface或class或其他变量时,注意类型的兼容性;如
interface Test{
    [index: string]: string;
}
//和以下的定义存在不兼容;type'string' 和 type'number'不兼容;可以改为兼容的类型;
interface Test{
    prop: number;
}
let test1 : Test = {prop: 67};//Error, 
                               //property'prop' is incompatible with index signature;
                               //type 'number' is not assignable to type 'string';
let test2 : Test = {str: 'str'};//Error, Property'prop' is missin in type '{str:string}'
//这个定义也会出问题;因为property'prop'与index signature不兼容;
interface Test1{
    prop: numbe
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值