2.TypeScript 基础入门(二)

变量类型的那些事

1.基本注解

类型注解使用:TypeAnnotation 语法。类型声明空间中可用的任何内容均可以用做类型注解。javascript

const num: number = 123;
function identity(num:number):number{
    return num;
}

复制代码

加入注解之后会报错的写法:java

const num: number = 123;
function identity(num: number): number {
  const num1 = '123'
  // 返回的不是 number  报错
  return num1;
}
const num1 = '123' 
// 参数不是 number 报错
identity(num1)
复制代码

2. 原始类型

Javascript原始类型也一样适用于 TypeScript的类型系统。所以,string, number,boolean也能够被用做类型注解:算法

let num: number;
 let str: string;
 let bool: boolean;

 num = 123;
 num = 123.45;
 num = '123'; //Type '"123"' is not assignable to type 'number'

 str = '123';
 str = 123; //Type '123' is not assignable to type 'string'

 bool = true;
 bool = false;
 bool = 'false';//Type '"false"' is not assignable to type 'boolean'.
复制代码

3. 数组

TypeScript 为数组提供了专用的类型语法,所以你能够很轻易的注解数组。它使用后缀[],接着你能够根据须要补充任何有效的类型注解(如:boolean[])。它能让你安全的使用任何有关数组的操做,并且它能放置一些相似赋值错误类型给成员的行为。数组

你有两种定义数组的方式:安全

第一种,你能够在元素类型后面接上[],表示由此类型元素组成的一个数组:bash

let list:number[] = [1,2,3]
复制代码

第二种方式是使用数组泛型,Array<元素类型>:数据结构

let list: Array<number> = [1,2,3]
复制代码

一个具体的栗子:编辑器

const boolArray: boolean[];

boolArray = [true, false];
console.log(boolArray[0]); // true
console.log(boolArray.length); // 2

boolArray[1] = true;
boolArray = [false, false];

boolArray[0] = 'false'; // Error
boolArray = 'false'; // Error
boolArray = [true, 'false']; // Error
复制代码

4.元组

元组类型容许表示一个已知元素数量和类型的数组,各元素的类型没必要相同。好比,你能够定义一对值分别为stringnumber类型的元组。ide

// 声明一个元组类型
let x: [string, number];
// 初始化赋值
x = ['hello', 10]; // OK
// 初始化错误
x = [10, 'hello']; // Error
复制代码

当访问一个已知索引的元素,会获得正确的类型:函数

console.log(x[0].substr(1)); // OK
console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'
复制代码

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

x[3] = 'world'; // OK, 字符串能够赋值给(string|number)类型
复制代码

可是我在编辑器里使用的时候是报错的,Index '2' is out-of-bounds in tuple of length 2,我也不知道为何??

5. 枚举

enum 类型是对JavaScript 标准数据类型的一个补充。使用枚举类型能够为一组数值赋予友好的名字。

enum Color {Red, Green, Blue}
let c: Color = Color.Green;
复制代码

默认状况下,从0开始为元素编号。你也能够手动的指定成员的编号。例如,咱们将上面的栗子改为从1开始编号:

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
复制代码

或者采用所有手动赋值:

enum Color {Red = 1,Geeen = 2, Blue = 4}
let c: Color = Color.Green
复制代码

编译后的js

var Color;
(function (Color) {
    Color[Color["Red"] = 1] = "Red";
    Color[Color["Green"] = 2] = "Green";
    Color[Color["Blue"] = 4] = "Blue";
})(Color || (Color = {}));
var c = Color.Green;
复制代码

全部的表达式都有返回值,它的返回值就是等号右边的赋值。

枚举类型提供的一个遍历是你能够由枚举的值获得它的名字。 例如,咱们知道数值为2,可是不肯定它映射到Color里的哪一个名字,咱们能够查找相应的名字:

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName);  // 显示'Green'由于上面代码里它的值是2
复制代码

这个试了一下不给数值number,发现没办法经过这个取值

enum Color {Red = 'r', Green = 'g', Blue = 'b'}
let c: Color = Color.Green;
console.log(c) // g
let colorName:string = Color[2]
console.log(colorName) // undefined
复制代码

咱们看一下编译后的javascript代码就明白了:

var Color;
(function (Color) {
   Color["Red"] = "r";
   Color["Green"] = "g";
   Color["Blue"] = "b";
})(Color || (Color = {}));
var c = Color.Green;
console.log(c);
var colorName = Color[2];
console.log(colorName);
复制代码

6. 特殊类型

6.1 any

any类型在 TypeScript类型系统中占有特殊的地位。它提供给你一个类型系统的【后门】,TypeScript将会把类型检查关闭。在类型系统里any可以兼容全部的类型(包括它本身)。所以,全部的类型都可以被赋值给它。它也能被赋值给其余任何类型。

let power: any;
//赋值任意类型
power = '123'
power = 123
let num:number;
num = power;
power = num;
复制代码

6.2 null 和 undefined

在类型系统中,JavaScript 中的 null 和 undefined 字面量和其余被标注了 any 类型的变量同样,都能被赋值给任意类型的变量,以下例子所示:

let num: numer;
let str: string;

// 这些类型能被赋予
num = null;
str = undefined;
复制代码

6.3 void

使用 :void来表示一个函数没有一个返回值

function log(message:string):void{
    console.log(message)
}
复制代码

声明一个void类型的变量没有什么大用,由于你只能为它赋予undefinednull

let unusable:void = undefined
复制代码

7.泛型

软件工程中,咱们不只要建立一致的定义良好的API,同时也要考虑可重用性。

不只可以支持当前的数据类型,同时也能支持将来的数据类型,这在建立大型系统时为你提供了十分灵活的功能。

举一个简单的演变例子:

当不实用泛型的时候,你的代码多是像这样:

function identity(arg:number):number{
    return arg;
}
复制代码

这个函数能够接收number 类型,返回的也是number类型,考虑到这个函数的可重用性,或者,咱们可使用any类型来定义函数像这样:

function identity(arg:any):any{
    return arg;
}
复制代码

使用any类型会致使这个函数能够接受任何类型的arg参数,且任何类型的值均可能被返回。

咱们须要一种方法使返回值的类型与传入参数的类型是相同的。 接下来咱们能够把代码像下面这样:

function identity<T>(arg:T):T{
    return arg
}
复制代码

咱们给 identity 添加了类型变量 T。 若是传入的类型(好比:number),咱们就能够知道返回的类型也是number。如今咱们就能够知道参数类型与返回值类型是相同的了。这有助于咱们跟踪函数里使用的类型的信息。

咱们把这个版本的identity函数叫作 泛型。 它可使用与多个类型,不一样于使用any,的不肯定性,还能保持像第一个例子同样的准确性参数类型返回值类型相同的。

7.1 泛型的使用

咱们定义了泛型函数之火,可使用两种方法使用。

第一种是传入全部的参数,包含类型参数:

let output = identity<string>('myString');//type of output will be 'string'
复制代码

这里咱们明确的指定了Tstring类型,并作为一个参数传给函数,而且肯定output的类型是string.

注意⚠️:使用<>不是()

第二种方法,利用类型推论--即编译器会根据传入的参数自动的帮助咱们肯定T的类型。

let output = identity("myString");// type of output will be 'string'
复制代码

这里并无使用(<>)来明确地传入类型;编译器能够查看myString的值,而后把T设置为它的类型。

7.2 使用泛型变量

使用泛型建立像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。换句话说,你必须把这些参数看成时任意或全部类型。

看下咱们以前写的泛型例子:

function identity<T>(arg:T):T{
    return arg
}
复制代码

当咱们试图在函数内输出arg.length的时候,编译器就会报错类型“T”上不存在属性“length”

function idenfity<T>(arg:T):T{
 console.log(arg.length) // Error: T doesn't have .length return arg } 复制代码

注意⚠️:

类型变量T表明的时任意类型,因此使用这个函数的人可能传入的是个数字,而数字时没有.length属性的。

而后咱们假设想操做T类型的数组而不直接是T,因为咱们操做的是数组,此时.length的属性应该是存在。

代码像这样:

function loggingIdentity<T>(arg: T[]):T[]{
console.log(arg.length) // Array has a .length,so no more error
return arg
}
复制代码

咱们能够这样理解loggingIdentity的类型:泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型T的数组。若是咱们传入数字数组,将返回一个数字数组,由于此时T的类型为number。这可让咱们把泛型变量T看成类型的一部分使用,而不是整个类型,增长了灵活性。

咱们还能够这样实现上面的例子:

function loggingIdentity<T>(arg:Array<T>):Array<T>{
console.log(arg.length)
return arg
}
复制代码

在计算机科学中,许多算法和数据结构并不会依赖于对象的实际类型。然而,你仍然会想在每一个变量里强制提供约束。

例如:在一个函数中,它接受一个列表,而且返回这个列表的反向排序,这里的约束是指传入至函数的参数与函数的返回值:

function reverse<T>(items:T[]):T[]{
  const toreturn = []
  for(let i = items.length - 1;i>=0;i--){
    toreturn.push(items[i])
  }
  return toreturn
}

const sample = [1,2,3]
let reversed = reverse(sample)

console.log(reversed)

reversed[0] = '1'; // Error
reversed = ['1', '2']; // Error

reversed[0] = 1; // ok
reversed = [1, 2]; // ok
复制代码

这个栗子中,函数reverse接受一个类型为T的数组items:T[],返回值为类型T的一个数组(注意:T[]),函数 reverse的返回值类型与它接受的参数类型同样。当你传入var sample = [1, 2, 3]时,TypeScript能推断出 reversenumber[]类型,从而能给你类型安全。于此类似,当你传递一个string[]类型的数组时,TypeScript能推断出为string[]类型, 如:

const strArr = ['1','2']
let reversedStrs = reverse(strArr)
reversedStrs = [1, 2]; // Error
复制代码

若是你的数组是const sample = [1,false,3]等同于const sample: (number | boolean)[],因此下面的代码也能能够的,若是是数组里有两种甚至三种类型的时候,它是可以推断出(number | boolean)这种或的类型的。也就是下面所说的联合类型。

function reverse<T>(items:T[]):T[]{
  const toreturn = []
  for(let i = items.length - 1;i>=0;i--){
    toreturn.push(items[i])
  }
  return toreturn
}

const sample = [1,false,3]
let reversed = reverse(sample)

console.log(reversed)

reversed[0] = true; // OK
reversed = [3, true]; // OK

reversed[0] = 1; // ok
reversed = [1, 2]; // ok
复制代码

8.联合类型

联合类型表示取值能够为多种类型中的一种。

8.1简单的例子

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven'
myFavoriteNumber = 7
复制代码
let myFavoriteNumber: string | number;
myFavoriteNumber = true;

// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
//   Type 'boolean' is not assignable to type 'number'

复制代码

联合类型使用|分隔每一个类型。

这里的let myFavoriteNumber: string | number;的含义是,容许myFavoriteNumber的类型是string或者number,可是不能是其余类型。

8.2 访问联合类型的属性或方法

TypeScript 不肯定一个联合类型的变量究竟是哪一个类型的时候,咱们只能访问此联合类型的全部类型里的共有的属性或方法

function getLength(something:string|number):number{
return something.length
}
// Error 类型“string | number”上不存在属性“length”。
  类型“number”上不存在属性“length”。
复制代码

上例中,length不是stringnumber的共有属性,因此会报错。

访问stringnumber的共有属性是没问题的:

function getLength(something:string|number):string{
    return something.toString()
}
复制代码

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:

let myFavoriteNumber:string|number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length)

myFavoriteNumber = 7
console.log(myFavoriteNumber.length) // Rrror 类型“number”上不存在属性“length”。

复制代码

上例中,第二行的myFavoriteNumber被推断成了string,访问它的length属性不会报错。而第四行的myFavoriteNumber被推断成了number,访问它的length属性时就报错了。

一个常见的用例是一个能够接受单个对象或者对象数组的函数:

function formatCommandline(command: string[] | string) {
  let line = '';
  if (typeof command === 'string') {
    line = command.trim();
  } else {
    line = command.join(' ').trim();
  }

  // Do stuff with line: string
}
复制代码
相关文章
相关标签/搜索