闽公网安备 35020302035485号
class DemoClass {
// 定义示例属性
name: string;
age: number;
location: string;
}
// 使用 var 或 let 定义变量,并使用 keyof 关键字
var variableName: keyof DemoClass;
variableName = "name"; // 示例赋值
let anotherVariableName: keyof DemoClass;
anotherVariableName = "age"; // 示例赋值
在上面的代码片段中,我们创建了一个名为 DemoClass 的类,并定义了三个属性:name、age 和 location。随后,我们使用 var 或 let 定义了两个变量 variableName 和 anotherVariableName,并使用 keyof 关键字调用 DemoClass。当我们为变量赋值时,TypeScript 会确保赋值的值是 DemoClass 的有效属性之一。function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
上面的函数使用了泛型来定义一个对象属性的类型。keyof T 返回的是字符串字面量类型的联合。字面量指的是赋值给常量变量的固定值。由于 K 是一个字符串字面量类型,我们使用 extends 关键字对 K 进行约束。索引操作符 obj[key] 返回属性所具有的相同类型。type Staff = {
name: string;
empCode: number;
};
const manager: Staff = {
name: 'Brian',
empCode: 100,
};
const nameType = getProperty(manager, 'name'); // 返回类型为 string
const empCodeType = getProperty(manager, 'empCode'); // 返回类型为 number
// const invalidType = getProperty(manager, 'sal'); // 编译错误
编译器会验证传递的键是否匹配类型 T 的属性名,因为我们对第二个参数应用了类型约束。如果我们尝试传递一个无效的键,比如 sal,编译器会报错。type keyProp = 'name' | 'empCode';
function getProperty<T, K extends keyProp>(obj: T, key: K): T[K] {
return obj[key];
}
尽管这种手动方式应用了相同类型的约束,但这种方法的可维护性较差。类型定义会重复,如果原始类型发生变化,手动定义的类型不会自动更新。type OptionsFlags<T> = {
[Property in keyof T]: boolean;
};
// 堆代码 duidaima.om
// 使用 OptionsFlags
type FeatureFlags = {
readingMode: () => void;
loggedUserProfile: () => void;
};
type UpdatedFeatures = OptionsFlags<FeatureFlags>;
输出结果:type UpdatedFeatures = {
readingMode: boolean;
loggedUserProfile: boolean;
}
在上面的代码片段中,OptionsFlags 被定义为一个包含类型参数 T 的泛型类型。[Property in keyof T] 定义了对类型 T 的属性名称的迭代,方括号表示索引签名语法。因此,OptionsFlags 会将所有 T 类型的属性值重新映射为 boolean 类型。type Partial<T> = {
[P in keyof T]?: T[P];
};
将所有属性设置为只读:type Readonly<T> = {
[P in keyof T]: readonly T[P];
};
四、 KeyOf 运算符与显式键interface User {
userName: string;
id: number;
}
function userData(user: User, property: keyof User) {
console.log(`Print user information ${property}: "${user[property]}"`);
}
let user = {
userName: "Karl",
id: 100
};
userData(user, "userName");
输出结果Print user information userName: "Karl"在上面的代码中,我们定义了一个 User 接口和一个 userData 函数。函数接受一个 User 对象和一个 User 类型的属性键,并打印相应的用户信息。
type stringMapDemo = {[key: string]: unknown};
function sampleStringPair(property: keyof stringMapDemo, value: string): stringMapDemo {
return {[property]: value};
}
我们定义了一个类型 stringMapDemo,它表示一个对象,其中所有键都是字符串类型,所有值的类型为 unknown。type OptionsFlags<T> = {
[Property in keyof T]: T[Property] extends Function ? T[Property] : boolean
};
type DemoFeatures = {
readingMode: () => void;
loggedUserProfile: () => void;
loginPassword: string;
userName: string;
};
type Features = OptionsFlags<DemoFeatures>;
运行后 Features 的类型结构如下type Features = {
readingMode: () => void;
loggedUserProfile: () => void;
loginPassword: boolean;
userName: boolean;
}
代码解析我们使用 OptionsFlags 来定义新类型 Features。通过条件映射,Features 类型中的方法保持不变,而字符串属性被映射为 boolean 类型。
type Record<K extends keyof any, T> = {
[P in K]: T;
};
示例type FeatureFlags = {
readingMode: () => void;
loggedUserProfile: () => void;
loginPassword: string;
userName: string;
};
我们可以使用 Record 实用类型将所有属性映射为 boolean 类型:type Features = Record<keyof FeatureFlags, boolean>;
// 结果类型
type Features = {
readingMode: boolean;
loggedUserProfile: boolean;
loginPassword: boolean;
userName: boolean;
};
Record 实际应用场景enum Status {
OPEN = "OPEN",
STARTED = "STARTED",
CLOSED = "CLOSED"
}
定义 Props 接口interface Props {
status: Status;
}
使用 Record 定义 statusMapconst statusMap: Record<Status, { label: string; color: "bg-red-400" | "bg-blue-400" | "bg-green-400" }> = {
OPEN: { label: "Open", color: "bg-red-400" },
STARTED: { label: "Started", color: "bg-blue-400" },
CLOSED: { label: "Closed", color: "bg-green-400" },
};
组件调用const TicketStatusBadge: React.FC<Props> = ({ status }) => {
return (
<Badge className={`
${statusMap[status].color}
text-background
hover:${statusMap[status].color}
`}>
{statusMap[status].label}
</Badge>
);
};
解析type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
示例type User = {
id: number;
name: string;
age: number;
email: string;
};
我们可以使用 Pick 类型选择 id 和 name 属性:type UserPreview = Pick<User, 'id' | 'name'>;
// 结果类型
type UserPreview = {
id: number;
name: string;
};
在这个例子中,UserPreview 类型只包含 id 和 name 属性。通过使用 TypeScript 的实用类型,如 Record 和 Pick,我们可以轻松地重构和简化类型定义。结合 keyof 运算符,我们可以确保类型的灵活性和安全性。