学习笔记
TypeScript 系列文章
- 【done】介绍
- 【done】复杂的数据类型
- A simple guide to “function” data type and function declaration syntax in TypeScriptopen in new window
- A simple guide to “interface” data type in TypeScriptopen in new window
- Introduction to “class” data type and Object-Oriented Programming paradigm in TypeScriptopen in new window
- Working with Enumerations (Enums) in TypeScriptopen in new window
- 类型系统
- 【done】Understanding the TypeScript’s type system and some must-know conceptsopen in new window
- 【done】Taking a look at must-know “utility types” provided by TypeScriptopen in new window
- 【done】Exploring the world of “Generics” (generic data types) in TypeScriptopen in new window
- A brief introduction to “Data Immutability” in TypeScriptopen in new window
- Let’s quickly understand how “Polymorphism” works in TypeScriptopen in new window
- 新的 ts/js 特性
- 【done】模块系统
- 【done】TypeScript 编译
- Understanding TypeScript’s “Compilation Process” & the anatomy of “tsconfig.json” file to configure TypeScript Compileropen in new window
- A brief introduction to TypeScript’s command-line interface and compiler settingsopen in new window
- A quick introduction to “Type Declaration” files and adding type support to your JavaScript packagesopen in new window
- Integrating TypeScript with Webpackopen in new window
其他文章
核心概念
类型
类型通过以下方式引入:
- 类型别名声明(
type sn = number | string;
) - 接口声明(
interface I { x: number[]; }
) - 类声明(
class C { }
) - 枚举声明(
enum E { A, B, C }
) - 指向某个类型的
import
声明
以上每种声明形式都会创建一个新的类型名称。
值
值是运行时名字,可以在表达式里引用。 比如let x = 5;
创建一个名为x
的值。
同样,以下方式能够创建值:
let
,const
,和var
声明- 包含值的
namespace
或module
声明 enum
声明class
声明- 指向值的
import
声明 function
声明
命名空间
类型可以存在于命名空间里。 比如,有这样的声明let x: A.B.C
, 我们就认为C
类型来自A.B
命名空间。这里,A.B
不是必需的类型或值。
简单的组合:一个名字,多种意义
一个给定的名字A
,我们可以找出三种不同的意义:一个类型,一个值或一个命名空间。 要如何去解析这个名字要看它所在的上下文是怎样的。 比如,在声明let m: A.A = A;
, A
首先被当做命名空间,然后做为类型名,最后是值。 这些意义最终可能会指向完全不同的声明!
内置组合
class
同时出现在类型和值里。class C {}
声明创建了两个东西: 类型C
指向类的实例结构,值C
指向类构造函数。枚举声明也拥有类似的行为。
用户组合
假设我们写了模块文件foo.d.ts
:
export var SomeVar: { a: SomeType };
export interface SomeType {
count: number;
}
2
3
4
这样使用它:
import * as foo from './foo';
let x: foo.SomeType = foo.SomeVar.a;
console.log(x.count);
2
3
这可以很好地工作,但是我们知道SomeType
和SomeVar
很相关。因此我们想让他们有相同的名字。我们可以使用组合通过相同的名字Bar
表示这两种不同的对象(值和对象):
export var Bar: { a: Bar };
export interface Bar {
count: number;
}
2
3
4
这提供了解构使用的机会:
import { Bar } from './foo';
let x: Bar = Bar.a;
console.log(x.count);
2
3
再次地,这里我们使用Bar
做为类型和值。 注意我们没有声明Bar
值为Bar
类型,它们是独立的。
高级组合
有一些声明能够通过多个声明组合。比如,class C { }
和interface C { }
可以同时存在并且都可以做为C
类型的属性。
只要不产生冲突就是合法的。一个普通的规则是值总是会和同名的其它值产生冲突除非它们在不同命名空间里,类型冲突则发生在使用类型别名声明的情况下(type s = string
),命名空间永远不会发生冲突。
让我们看看如何使用。
利用 interface 添加
我们可以使用一个interface
往另一个interface
声明里添加额外成员:
interface Foo {
x: number;
}
// ... elsewhere ...
interface Foo {
y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK
2
3
4
5
6
7
8
9
这同样作用于类:
class Foo {
x: number;
}
// ... elsewhere ...
interface Foo {
y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK
2
3
4
5
6
7
8
9
注意我们不能使用接口往类型别名里添加成员(type s = string;
)
使用 namespace 添加
namespace
声明可以用来添加新类型,值和命名空间,只要不出现冲突。
比如,我们可能添加静态成员到一个类:
class C {
}
// ... elsewhere ...
namespace C {
export let x: number;
}
let y = C.x; // OK
2
3
4
5
6
7
注意在这个例子里,我们添加一个值到C
的静态部分(它的构造函数)。这里因为我们添加了一个值,且其它值的容器是另一个值(类型包含于命名空间,命名空间包含于另外的命名空间)。
我们还可以给类添加一个命名空间类型:
class C {
}
// ... elsewhere ...
namespace C {
export interface D { }
}
let y: C.D; // OK
2
3
4
5
6
7
在这个例子里,直到我们写了namespace
声明才有了命名空间C
。作为命名空间的C
不会与类创建的值C
或类型C
相互冲突。
最后,我们可以通过namespace
声明进行不同的合并。这不是特别实际的示例,但是可以展示所有有趣的行为。
namespace X {
export interface Y { }
export class Z { }
}
// ... elsewhere ...
namespace X {
export var Y: number;
export namespace Z {
export class C { }
}
}
type X = string;
2
3
4
5
6
7
8
9
10
11
12
13
在这个例子里,第一个代码块创建了以下名字与含义:
- 一个值
X
(因为namespace
声明包含一个值,Z
) - 一个命名空间
X
(因为namespace
声明包含一个值,Z
) - 在命名空间
X
里的类型Y
- 在命名空间
X
里的类型Z
(类的实例结构) - 值
X
的一个属性值Z
(类的构造函数)
第二个代码块创建了以下名字与含义:
- 值
Y
(number
类型),它是值X
的一个属性 - 一个命名空间
Z
- 值
Z
,它是值X
的一个属性 - 在
X.Z
命名空间下的类型C
- 值
X.Z
的一个属性值C
- 类型
X
使用 export= 或 import
一个重要的原则是export
和import
声明会导出或导入目标的所有含义。
其他语法
import q = x.y.z
- 简化命名空间操作的方法,给常用的
x.y.z
起个短的名字q
- 详见TypeScript - Namespaces - Aliasesopen in new window
- 简化命名空间操作的方法,给常用的