原始类型与字面量类型
原始类型
TypeScript中的原始类型与JavaScript基本一致,包括number
、string
、boolean
、null
、undefined
、symbol
和bigint
。这些类型表示最基本的不可再分的数据单元。
let age: number = 25;
let name: string = "Alice";
let isActive: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
let uniqueKey: symbol = Symbol("key");
let bigNumber: bigint = 9007199254740991n;
原始类型的特点是不可变性,一旦创建就不能被修改。TypeScript会对这些类型进行严格的类型检查:
let price: number = 100;
price = "200"; // 错误:不能将类型"string"分配给类型"number"
字面量类型
字面量类型是TypeScript特有的类型系统特性,它允许我们将值本身作为类型。字面量类型分为字符串字面量、数字字面量和布尔字面量三种。
字符串字面量类型
type Direction = "north" | "south" | "east" | "west";
function move(direction: Direction) {
console.log(`Moving ${direction}`);
}
move("north"); // 正确
move("up"); // 错误:类型"up"的参数不能赋给类型"Direction"的参数
字符串字面量类型常用于定义有限的字符串集合,如API端点、状态码等。
数字字面量类型
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
function rollDice(): DiceRoll {
return Math.floor(Math.random() * 6) + 1 as DiceRoll;
}
const result: DiceRoll = rollDice();
console.log(`You rolled a ${result}`);
数字字面量类型适用于固定数值范围的场景,如骰子点数、HTTP状态码等。
布尔字面量类型
type Yes = true;
type No = false;
function confirmAction(confirmation: Yes | No): void {
if (confirmation) {
console.log("Action confirmed");
} else {
console.log("Action cancelled");
}
}
confirmAction(true); // 正确
confirmAction(false); // 正确
confirmAction(1); // 错误
布尔字面量类型虽然使用较少,但在需要严格区分true/false的场景下很有用。
联合类型与字面量
字面量类型常与联合类型结合使用,创建更精确的类型约束:
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
function fetchData(method: HttpMethod, url: string) {
// 实现fetch逻辑
}
fetchData("GET", "/api/users"); // 正确
fetchData("OPTIONS", "/api/users"); // 错误
这种模式在Redux的action类型定义中特别常见:
type Action =
| { type: "ADD_TODO"; text: string }
| { type: "TOGGLE_TODO"; id: number }
| { type: "DELETE_TODO"; id: number };
function todoReducer(state: Todo[], action: Action): Todo[] {
switch (action.type) {
case "ADD_TODO":
return [...state, { id: Date.now(), text: action.text, completed: false }];
case "TOGGLE_TODO":
return state.map(todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case "DELETE_TODO":
return state.filter(todo => todo.id !== action.id);
default:
return state;
}
}
类型推断与字面量
TypeScript能自动推断字面量类型,但有时需要明确指定:
const name = "Alice"; // 类型推断为"Alice"(字面量类型)
let age = 25; // 类型推断为number
// 明确指定字面量类型
const direction: "north" = "north";
使用as const
断言可以将对象或数组的属性转换为字面量类型:
const colors = ["red", "green", "blue"] as const;
// 类型为 readonly ["red", "green", "blue"]
const user = {
name: "Alice",
age: 25,
active: true
} as const;
// 类型为 { readonly name: "Alice"; readonly age: 25; readonly active: true; }
模板字面量类型
TypeScript 4.1引入了模板字面量类型,可以基于字符串字面量创建更复杂的类型:
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiEndpoint = `/api/${string}`;
function callApi(method: HttpMethod, endpoint: ApiEndpoint) {
// 实现API调用
}
callApi("GET", "/api/users"); // 正确
callApi("POST", "/data/products"); // 错误:不是以/api/开头
模板字面量类型可以与条件类型结合,创建强大的类型工具:
type GetterName<T extends string> = `get${Capitalize<T>}`;
type NameGetter = GetterName<"name">; // "getName"
type AgeGetter = GetterName<"age">; // "getAge"
function createGetter<T extends string>(property: T): GetterName<T> {
return `get${property.charAt(0).toUpperCase() + property.slice(1)}` as GetterName<T>;
}
const getName = createGetter("name"); // 类型为"getName"
const getAge = createGetter("age"); // 类型为"getAge"
枚举与字面量类型
枚举和字面量联合类型在某些场景下可以互换,但各有优缺点:
// 使用枚举
enum Direction {
North = "NORTH",
South = "SOUTH",
East = "EAST",
West = "WEST"
}
// 使用字面量联合类型
type Direction = "NORTH" | "SOUTH" | "EAST" | "WEST";
// 枚举提供反向映射
console.log(Direction.North); // "NORTH"
console.log(Direction["NORTH"]); // "North"
// 字面量类型更轻量,但需要手动维护值
const directions = {
North: "NORTH",
South: "SOUTH",
East: "EAST",
West: "WEST"
} as const;
性能考虑
字面量类型在编译时会被擦除,不会影响运行时性能。但大量使用复杂的联合字面量类型可能会增加编译时间:
// 简单的字面量联合 - 编译快
type SmallUnion = "A" | "B" | "C";
// 复杂的字面量联合 - 可能增加编译时间
type LargeUnion =
| "A1" | "A2" | "A3" | "A4" | "A5"
| "B1" | "B2" | "B3" | "B4" | "B5"
| "C1" | "C2" | "C3" | "C4" | "C5"
// ...更多字面量
| "Z99";
类型守卫与字面量
在处理字面量类型时,类型守卫特别有用:
type Result = { status: "success"; data: string } | { status: "error"; message: string };
function handleResult(result: Result) {
if (result.status === "success") {
console.log(result.data); // 这里result被推断为{ status: "success"; data: string }
} else {
console.error(result.message); // 这里result被推断为{ status: "error"; message: string }
}
}
配置模式中的应用
字面量类型非常适合配置对象的类型定义:
type LogLevel = "debug" | "info" | "warn" | "error";
interface LoggerConfig {
level: LogLevel;
format: "json" | "text";
timestamp: boolean;
}
function createLogger(config: LoggerConfig) {
// 实现logger创建逻辑
}
createLogger({
level: "info",
format: "json",
timestamp: true
}); // 正确
createLogger({
level: "verbose", // 错误:不是有效的LogLevel
format: "yaml", // 错误:不是有效的format
timestamp: "yes" // 错误:应为boolean
});
与泛型结合
字面量类型可以与泛型结合,创建灵活的API:
type EventMap = {
click: { x: number; y: number };
keypress: { key: string; code: number };
scroll: { position: number };
};
function addEventListener<T extends keyof EventMap>(
event: T,
handler: (payload: EventMap[T]) => void
) {
// 实现事件监听
}
addEventListener("click", (payload) => {
console.log(payload.x, payload.y); // payload被正确推断为{ x: number; y: number }
});
addEventListener("keypress", (payload) => {
console.log(payload.key); // payload被正确推断为{ key: string; code: number }
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:热力图(Heatmap)实现
下一篇:数组与元组类型