TypeScript字面量类型扩展和无类型导入10bet

来源:http://www.chinese-glasses.com 作者:Web前端 人气:157 发布时间:2020-03-24
摘要:时间: 2019-11-13阅读: 65标签: 字面量扩展字面量类型 前言 TypeScript 是 JavaScript的一个超集,主要提供了类型系统和对 ES6 的支持,它由 Microsoft开发, 代码开源于 GitHub 上。 第一个版本发布

时间: 2019-11-13阅读: 65标签: 字面量扩展字面量类型

前言

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持,它由 Microsoft 开发,代码开源于 GitHub 上。

第一个版本发布于 2012 年 10 月,经历了多次更新后,现在已成为前端社区中不可忽视的力量,不仅在 Microsoft 内部得到广泛运用,而且 Google 的 Angular2 也使用了 TypeScript 作为开发语言。
TypeScript :官方手册及其非官方中文版
前置知识:JavaScript、ECMAScript6

当使用const关键字声明局部变量并使用字面量值初始化它时,TypeScript 将推断该变量的字面量类型:

简介

官网的定义:

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source.

翻译成中文即是:

TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。

优势:

  1. 增加代码可读性和可维护性
  2. 拥有活跃的社区
  3. TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名为 .ts 即可
  4. 即使不显式的定义类型,也能够自动做出类型推论
  5. 可以定义从简单到复杂的一切类型
  6. 即使 TypeScript 编译报错,也可以生成 JavaScript 文件
  7. 兼容第三方库,即使第三方库不是用 TypeScript 写的,也可以> 编写单独的类型文件供 TypeScript 读取

TypeScript的安装:

npm install -g typescript

TypeScript文件编译,使用tsc命令:

tsc hello.ts

支持TypeScript的编辑器:

Visual Studio Code(推荐使用)
Sublime Text
Atom
WebStorm
Vim
Emacs
Eclipse
Visual Studio 2015
Visual Studio 2013

const stringLiteral = ""; // Type ""const numericLiteral = 42; // Type 42const booleanLiteral = true; // Type true

基础

  • 原始数据类型
  • 任意值
  • 类型推论
  • 联合类型
  • 接口
  • 数组
  • 函数
  • 类型断言
  • 声明文件
  • 内置对象

由于const关键字,每个变量的值都不能更改,所以字面量类型非常有意义。它保存了关于被赋值的确切信息。

原始数据类型

JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。

原始数据类型包括:布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol。

如果如果let声明上述的变量,那么每个字面量类型都被扩展为相应的扩展类型:

布尔值

布尔类型,使用boolean定义

let isDone: boolean = false;
//或者
let createdByBoolean: boolean = Boolean(1);

布尔对象,使用Boolean构造函数

let createdByNewBoolean: Boolean = new Boolean(1);
let widenedStringLiteral = stringLiteral; // Type stringlet widenedNumericLiteral = numericLiteral; // Type numberlet widenedBooleanLiteral = booleanLiteral; // Type boolean

数值

数值类型,使用number定义

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法(ES6)
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法(ES6)
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;

数值对象,使用Number构造函数

与const变量相反,使用let声明的变量是可以修改的。如果 TypeScript 为let变量推断一个字面量类型,那么尝试为指定的值以外的任何值赋值都会在编译时产生错误。

字符串

字符串类型,使用string定义:

let myName: string = 'Xcat Liu';
let myAge: number = 25;

// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
// 模板字符串编译结果
//var sentence = "Hello, my name is " + myName + //".nI'll be " + (myAge + 1) + " years old next //month.";

其中 ` 用来定义 ES6 中的模板字符串,${expr} 用来在模板字符串中嵌入表达式。

因此,对于上述每个let变量,都会推断出扩展的类型,枚举字面量也是如此:

空值

JavaScript 没有空值(Void)的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数:

function alertName(): void {
  alert('My name is xcatliu');
}

声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:

let unusable: void = undefined;
enum FlexDirection { Row, Column}const enumLiteral = FlexDirection.Row; // FlexDirection.Row 类型let widenedEnumLiteral = enumLiteral; // FlexDirection 类型

Null 和 Undefined

在 TypeScript 中,可以使用 null 和 undefined 来定义这两个原始数据类型:

let u: undefined = undefined;
let n: null = null;

undefined 类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null。

与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量,而 void 类型的变量不能赋值给 number 类型的变量:

// 这样不会报错
let num: number = undefined;
// 这样也不会报错
let u: undefined;
let num: number = u;

总结一下,下面是扩大字面量类型的规则:

任意值

  • 如果是一个普通类型,在赋值过程中改变类型是不被允许的,但
    如果是 any 类型,则允许被赋值为任意类型。

  • 任意值(Any)用来表示允许赋值为任意类型。

  • 在任意值上访问任何属性都是允许的,也允许调用任何方法。

  • 声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值

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

let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
let anyThing: any = 'hello';
console.log(anyThing.myName);
anyThing.setName('Jerry Lee').sayHello();

字符串字面量类型被扩展为string类型数字字面量类型被扩展为number类型布尔字面量类型被扩展为boolean类型枚举字面量类型被扩展为包含枚举的类型

类型推论

如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。

TypeScript 2.1 中,编译器会考虑对 myFavoriteNumber 的最后一次赋值来检查类型。

let myFavoriteNumber = 'seven';
//等价于let myFavoriteNumber: string = 'seven';

到目前为止,咱们一直在研究字面量类型的扩展,在必要时自动扩展。现在来看看非扩展字面量类型,如名所示,它们不会自动地扩展。

联合类型

  • 联合类型(Union Types)表示取值可以为多种类型中的一种。
  • 联合类型使用 | 分隔每个类型。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

这里的 string | number 的含义是,允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型。

访问联合类型的属性和方法:

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法。

function getString(something: string | number): string {
  return something.toString();
  //ERROR return something.length;
}

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

非扩展字面量类型

接口

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

interface Person {
  name: string;
  age: number;
}

使用接口类型赋值的时候,变量的形状必须和接口的形状保持一致。属性数量和类型保持一致,不允许添加未定义的属性。

let xcatliu: Person = {
  name: 'Xcat Liu',
  age: 25,
};

可选属性,有时我们希望不要完全匹配一个形状,那么可以用可选属性。使用”?”

interface Person {
  name: string;
  age?: number;
}

let xcatliu: Person = {
  name: 'Xcat Liu',
};

任意属性,有时候我们希望一个接口允许有任意的属性

interface Person {
  name: string;
  age?: number;
  [propName: string]: any;
}

let xcatliu: Person = {
  name: 'Xcat Liu',
  website: 'http://xcatliu.com',
};

注意:一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性

interface Person {
  name: string;
  age?: number;
  [propName: string]: string;
}

let xcatliu: Person = {
  name: 'Xcat Liu',
  age: 25,//error,25是number类型,不是string的子属性
  website: 'http://xcatliu.com',
};

只读属性,对象中的一些字段只能在创建的时候被赋值,用 readonly 定义只读属性。

注意:只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

interface Person {
  readonly id: number;
}
//第一次给对象赋值,激活只读约束
let xcatliu: Person = {
  id: 89757,
};

xcatliu.id = 9527;//error

可以通过显式地将变量标注为字面量类型来创建非扩展字面量类型的变量

数组

定义数组:有多种定义方式

  1. 「类型 + 方括号」表示法

    let fibonacci: number[] = [1, 1, 2, 3, 5];

数组的项中不允许出现其他的类型

  1. 使用数组泛型(Generic) Array 来表示数组

    let fibonacci: Array = [1, 1, 2, 3, 5];

  2. 用接口表示数组

interface NumberArray {
  [index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
//NumberArray 表示:只要 index 的类型是 number,那么值的类型必须是 number。
  1. any 表示数组中允许出现任意类型
let list: any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];
  1. 类数组
    常见的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection (内置对象)等
function sum() {
  let args: IArguments = arguments;
}
const stringLiteral: "" = ""; // 类型 "" (非扩展)const numericLiteral: 42 = 42; // 类型 42 (非扩展)

函数

(1)定义函数的两种方式:函数申明,函数表达式

  1. 函数申明
function sum(x: number, y: number): number {
  return x + y;
}

调用时输入多余的(或者少于要求的)参数,是不被允许的。

  1. 函数表达式
let mySum = function (x: number, y: number): number {
  return x + y;
};

上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。

(2)接口中的函数

interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
  return source.search(subString) !== -1;
}

(3)函数中参数

  1. 可选参数(使用”?”表示)

    function buildName(firstName: string, lastName?: string) {}

注意:可选参数后不允许出现必须参数(参数默认值除外)

  1. 参数默认值

    function buildName(firstName: string = 'Xcat', lastName: string) {}

在 ES6 中,TypeScript 会将添加了默认值的参数识别为可选参数,此时不受可选参数位置限制

  1. 剩余参数(rest参数)

    function push(array, ...items) { items.forEach(function(item) {

     array.push(item);
    

    }); } //items 是一个数组。所以我们可以用数组的类型来定义它 function xpush(array: any[], ...items: any[]) { items.forEach(function(item) {

     array.xpush(item);
    

    }); }

**注意:**rest参数只能是函数中最后一个参数
(4)函数重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {...}

将非扩展字面量类型的变量的值赋给另一个变量,该变量将不会扩展。

类型断言

类型断言(Type Assertion)可以用来绕过编译器的类型推断,手动指定一个值的类型(即程序员对编译器断言)。

类型断言不是类型转换。

(1)语法:

<类型>值

// 或

值 as 类型

// 在TSX语法 (React的JSX语法的TS版)中必须用后一种

(2)例子:使用类型断言,将一个联合类型的变量指定为一个更加具体的类型。

function toBoolean(something: string | number): boolean {
  return <string>something;
}

function getLength(something: string | number): number {
  let length=something.length;//error
  let xlength=something.length;//OK
}

注意:只能断言成联合类型中存在的类型。

let widenedStringLiteral = stringLiteral; // 类型 "" (非扩展)let widenedNumericLiteral = numericLiteral; // 类型 42 (非扩展)

声明文件

当时用第三方库时,我们需要引用它的声明文件。

申明语句:使用declare关键字来定义类型

如:我们需要使用第三方库Jquery获取一个id是foo的元素

declare var jQuery: (string) => any;//类型声明
jQuery('#foo');//单独书写时typescript并不识别$或者jquery

通常我们会将类型声明放在一个单独的文件中,约定声明文件以.d.ts为后缀。

// jQuery.d.ts

declare var jQuery: (string) => any;

使用声明文件:用「三斜线指令」表示引用了声明文件

/// <reference path="./jQuery.d.ts" />

jQuery('#foo');

TypeScript2.0推荐使用@types来管理,即使用nm安装对应声明模块

如:npm install @types/jquery --save-dev

官方搜索声明文件链接:http://microsoft.github.io/TypeSearch/

非扩展字面量类型的好处

内置对象

内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

这些定义文件都在 TypeScript 核心库的定义文件中:

ES标准提供的内置对象有:
Boolean、Error、Date、RegExp 等

DOM 和 BOM 提供的内置对象有:
Document、HTMLElement、Event、NodeList 等

注意: Node.js不是内置对象的一部分,需要引入声明文件:
npm install @types/node --save-dev

为了理解非扩展字面量类型的是有用的,咱们再来看看扩展字面量类型。在下面的例子中,一个数组是由两个可扩展字符串字面量类型的变量创建的:

进阶

  • 类型别名
  • 字符串字面量类型
  • 元组
  • 枚举
  • 类与接口
  • 泛型
  • 声明合并
  • 扩展阅读
const http = "http"; // Type "http" (可扩展)const  = ""; // Type "" (可扩展)const protocols = [http, ]; // Type string[]const first = protocols[0]; // Type stringconst second = protocols[1]; // Type string

类型别名

使用 ‘type’ 创建类型别名,类型别名用来给一个类型起个新名字。类型别名常用于联合类型。

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {...}

TypeScript 推断数组protocols的类型为string[]。因此,像first和second这样的数组元素类型被扩展为string。字面量类型"http"和""的概念在扩展过程中丢失了。

字符串字面量

字符串字面量类型用来约束取值只能是某几个字符串中的一个。

类型别名与字符串字面量类型都是使用 ‘type’ 进行定义。

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
  // do something
}

handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'

如果咱们显式地将这两个常量指定为非扩展类型,则protocols数组将被推断为类型("http" | "")[],它表示一个数组,其中仅包含字符串"http"或"":

元组

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象

元组起源于函数编程语言(如 F#),在这些语言中频繁使用元组。

const  "http" = "http"; // Type "http" (非扩展)const  "" = ""; // Type "" (非扩展const protocols = [http, ]; // Type ("http" | "")[]const first = protocols[0]; // Type "http" | ""const second = protocols[1]; // Type "http" | ""

(1)定义元组:

let tuple: [string, number];

let xtuple: [string, number] = ['Xcat Liu', 25];

现在first和second的类型被推断为"http" | ""。这是因为数组类型没有对索引0处的值"http"和索引1处的值""进行编码。它只是声明该数组只包含两个字面量类型的值,不管在哪个位置。

(2)元组的赋值:

1.定义元组时赋值

let xtuple: [string, number] = ['Xcat Liu', 25];

2.使用元组索引赋值,索引从0开始,可只赋值其中一项

xcatliu[0] = 'Xcat Liu';

3.直接对元组赋值,需要提供所有元组类型中指定的项。

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25];

4.越界元素赋值

当赋值给越界的元素时,它类型会被限制为元组中每个类型的联合类型。

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25, 'http://xcatliu.com/'];
//'http://xcatliu.com/'满足联合类型 string | number

如果出于某种原因,希望保留数组中字符串字面量类型的位置信息,可以用如下的方式显示指定:

(3)元组元素的访问

1.使用索引访问

let xcatliu: [string, number] = ['Xcat Liu', 25];
xcatliu[0].slice(1);
xcatliu[1].toFixed(2);

2.访问越界元素

当访问一个越界的元素,也会识别为元组中每个类型的联合类型。(如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的属性或方法-联合类型)

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25, 'http://xcatliu.com/'];

console.log(xcatliu[2].slice(1));//error

// index.ts(4,24): error TS2339: Property 'slice' does not exist on type 'string | number'.
const http = "http"; // Type "http" (可扩展)const  = ""; // Type "" (可扩展)const protocols: ["http", ""] = [http, ]; // Type ["http", ""]const first = protocols[0]; // Type "http" (非扩展)const second = protocols[1]; // Type "" (非扩展)

枚举

现在,first和second被推断为各自的非扩展字符串字面量类型。

(1)定义

使用 ‘enum’ 关键字来定义枚举类型;

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

本文由10bet发布于Web前端,转载请注明出处:TypeScript字面量类型扩展和无类型导入10bet

关键词:

上一篇:没有了

下一篇:没有了

最火资讯