对象如果描述了类型也需要严格执行。
const pt : {
x : number,
y : number
} = {x : 100, y : 100}
pt.z = 10000 // Error
可选项:
function printName(obj : {first : string, last ? string}) {
}
printName({first :'Bob'})
printName({first :'Alice', last : "Alisson"})
? 表达式
?代表可能是undefined,但是安全很多。
const o : {
a : string,
b ? : {
c : string
}
} = {a : "1"}
console.log(o.b?.c) // undefined
o.b?.c = "Hello" // Error
联合
function printId(id: number | string) {
console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error
printId({ myID: 22342 });
联合类型只能使用两个类型的公共操作。
function printId(id: number | string) {
console.log(id.toUpperCase());
// Property 'toUpperCase' does not exist on type 'string | number'.
}
Typescript会针对联合类型做排除法:
function printID(id : number | string) {
if(typeof id === 'number') {
console.log(id)
return
}
console.log(id.toUpperCase())
}
这个也叫做类型窄化技术(后面我们会有单独一节介绍)
类型别名
type 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 });
类型别名也可以使用联合:
type ID = number | string
注意,别名只是别名,例如:
let x : ID = 100
// typeof x === 'number'
当然别名可以和它代表的类型一起工作(因为别名不是创建了新的类型):
let id : ID = "abc"
id = 456 // OK
接口
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 });
有时候Ts对类型的理解没有你多,这个时候你就需要用类型断言:
const myCanvas =
// HTMLElement
document.getElementById("main_canvas") as HTMLCanvasElement;
通常TS会接收“说的通”的类型断言。
比如: 父类 as 子类, 联合 as 单个。
但是有的类型断言TS会拒绝,比如:
const x = 'hello' as number
TS会报一个这样的错误:Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
当然有时候你可以用any as T来“欺骗”TS,或者说蒙混过关:
const a = (expr as unknown) as T;
可以用字面类型来约束一些特殊的函数,比如:
function compare(a: string, b: string): -1 | 0 | 1 {
return a === b ? 0 : a > b ? 1 : -1;
}
当然下面是一个更加贴近真实场景的例子:
interface Options {
width: number;
}
function configure(x: Options | "auto") {
// ...
}
configure({ width: 100 });
configure("auto");
configure("automatic"); // Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'.
字面类型的一个坑:
function handleRequest(url : string, method : "GET" | "POST") {
// do...
}
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
// Error : Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.
// 1
const req = { url: "https://example.com", method: "GET" as "GET" };
// 2
handleRequest(req.url, req.method as "GET");
// 3
const req = { url: "https://example.com", method: "GET" } as const
enum Direction {
Up = 1,
Down,
Left,
Right,
}
上面的含义, Down = 2, Left = 3, Right = 4
枚举类型最后会被翻译成整数,因此枚举的很多性质和整数相似。比如Down.toString()会返回2,而不是Down 。正因为如此,枚举类型的效率很高。
当然如果你想用字符串类的枚举(个人觉得没有必要),就需要显示的为每一项赋值:
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
当然也可以混合,不过非但没有意义,而且会减少代码的可读性:
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
在运行时,Enum会被解释成对象,Enum的每项会被解释成常数。
下面这个例子可以很好的证明。
enum E {
X,
Y,
Z,
}
function f(obj: { X: number }) {
return obj.X;
}
f(E)
可以用下面这个语法提取Enum中的字符串,这个也叫Reverse Mapping。
E[E.X] // X
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!