TypeScript$Type-Define-TypeAliasAndInterface
1. Type Alias
就像值可以通过字面量 literal 来表示,也可以声明一个变量 variable 来接收。类型也可以通过字面量 literal 来表示,或者通过 type alias 来接收。Type alias 像是 const,不可以重新赋值。
type alias: a name for any type.
type Point = {
x: number; // ; | , | new line
y: number;
};
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
type ID = number | string;
1.1 Inheritance in type aliases - Intersection & type
使用 & 来表示 extends。(因为最终的结果是两方面都得满足)
// Extending a type via intersections
type Animal = {
name: string;
}
type Bear = Animal & {
honey: boolean;
}
const bear = getBear();
bear.name;
bear.honey;
1.2 Recursion Types
Recursive types, are self-referential, and are often used to describe infinitely nestable types.
type NestedNumbers = number | NestedNumbers[]
const val: NestedNumbers = [3, 4, [5, 6, [7], 59], 221]
if (typeof val !== "number") {
val.push(41)
val.push("this will not work")
// error, Argument of type 'string' is not assignable to parameter of type 'NestedNumbers'.
}
1.3 type JSON
type JSONPrimitive = string | number | boolean | null
type JSONObject = { [k: string]: JSONValue }
type JSONArray = JSONValue[]
type JSONValue = JSONArray | JSONObject | JSONPrimitive
////// DO NOT EDIT ANY CODE BELOW THIS LINE //////
function isJSON(arg: JSONValue) {}
// POSITIVE test cases (must pass)
isJSON("hello")
isJSON([4, 8, 15, 16, 23, 42])
isJSON({ greeting: "hello" })
isJSON(false)
isJSON(true)
isJSON(null)
isJSON({ a: { b: [2, 3, "foo"] } })
// NEGATIVE test cases (must fail)
// @ts-expect-error
isJSON(() => "")
// @ts-expect-error
isJSON(class {})
// @ts-expect-error
isJSON(undefined)
// @ts-expect-error
isJSON(BigInt(143))
// @ts-expect-error
isJSON(isJSON)
2. Interfaces
interface 用来表示对象类型。既然有了 type alias,为什么还需要 interface 呢?因为 type alias 是个类似 const 的别名——不能重复,不能扩展。而 interface 和 type alias 最大的不同是 interface 是可以扩展的——多次声明同一个 interface 时,会合并为一个。(当然更明显的区别是 interface 只能用来声明对象类型)
interface declaration: another way to name an object type.
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
2.1 Inheritance in interfaces: extends and implements
implements 也可以实现 type,要求是对象。
// Extending an interface
interface Animal {
name: string;
}
interface Bear extends Animal {
honey: boolean;
}
const bear = getBear();
bear.name;
bear.honey;
class LivingOrganism {
isAlive() {
return true
}
}
interface AnimalLike {
eat(food): void
}
interface CanBark {
bark(): string
}
class Dog2
extends LivingOrganism
implements AnimalLike, CanBark
{
bark() {
return "woof"
}
eat(food) {
consumeFood(food)
}
}
- Differences Between Type Aliases and Interfaces
If you would like a heuristic, use interface until you need to use features from type.
官网中还列出了 type aliases 和 interface 其他的不同:
- Prior to TypeScript version 4.2, type alias names may appear in error messages, sometimes in place of the equivalent anonymous type (which may or may not be desirable). Interfaces will always be named in error messages.
- Type aliases may not participate in declaration merging, but interfaces can.
- Interface names will always appear in their original form in error messages, but only when they are used by name.
- Using interfaces with
extendscan often be more performant for the compiler than type aliases with intersections.