TS 类型体操练习 2
keyof
keyof
是 TypeScript 中的一个操作符,用于获取类型的所有键的联合类型
对于一个对象类型,keyof
可以用于获取该对象的所有属性名的联合类型
type Person = {
name: string;
age: number;
address: string;
};
type Keys = keyof Person; // 类型为 "name" | "age" | "address"
extends
extends
是 TypeScript 中的一个关键字,主要用于泛型约束和条件类型。- 在泛型约束中,
extends
用于限制泛型类型必须是某个类型的子类型。 - 在条件类型中,
extends
用于判断一个类型是否可以赋值给另一个类型。
type MyType<T> = T extends string ? number : boolean;
type Result = MyType<string>; // number
Exclude
Exclude from T
those types that are assignable to U
从联合类型 T
中排除 U
中的类型,来构造一个新的类型。
type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
实现:
在 TypeScript 中,extends
关键字在条件类型表示子类型关系或类型的赋值关系
。
type MyExclude<T, U> = T extends U ? never : T;
在 MyExclude
的实现中,T extends U ? never : T
的意思是如果类型 T
能够赋值给类型 U
,即 T
是 U
的子类型,那么返回 never
类型,否则返回 T
类型。这样的实现就实现了从类型 T
中排除了类型 U
Trim
Implement Trim<T>
which takes an exact string type and returns a new string with the whitespace from both ends removed.
实现Trim<T>
,它接受一个明确的字符串类型,并返回一个新字符串,其中两端的空白符都已被删除。
type trimed = Trim<' Hello World '> // expected to be 'Hello World'
测试用例
type cases = [
Expect<Equal<Trim<"str">, "str">>,
Expect<Equal<Trim<" str">, "str">>,
Expect<Equal<Trim<" str">, "str">>,
Expect<Equal<Trim<"str ">, "str">>,
Expect<Equal<Trim<" str ">, "str">>,
Expect<Equal<Trim<" \n\t foo bar \t">, "foo bar">>,
Expect<Equal<Trim<"">, "">>,
Expect<Equal<Trim<" \n\t ">, "">>
];
实现:
- 先处理最左边的空字符串,包括
" "
,"\t"
,"\n"
, S符合模版字符串,则说明其最左边元素类型为空字符串,则取除了首字符外的剩余字符串递归处理,否则就返回S,达到处理最左边字符串的效果
type Trim<S extends string> = S extends `${" " | "\t" | "\n"}${infer R}`
? Trim<R>
: S;
- 同理处理右边空字符串:
type Trim<S extends string> = S extends `${infer L}${" " | "\t" | "\n"}`
? Trim<L>
: S;
- 综合:第一个条件类型用于移除开头的空格字符,第二个条件类型用于移除结尾的空格字符。每个条件类型都通过模板字面量类型检查字符串的开头或结尾是否为空格字符,然后递归调用
Trim
类型直到字符串不再以空格字符开头或结尾。
type Trim<S extends string> = S extends `${" " | "\t" | "\n"}${infer R}`
? Trim<R>
: S extends `${infer L}${" " | "\t" | "\n"}`
? Trim<L>
: S;
MyCapitalize
Implement Capitalize<T>
which converts the first letter of a string to uppercase and leave the rest as-is.
实现 Capitalize<T>
它将字符串的第一个字母转换为大写,其余字母保持原样。
type capitalized = Capitalize<'hello world'> // expected to be 'Hello world'
实现:
type MyCapitalize<S extends string> = S extends `${infer L}${infer R}`
? `${Uppercase<L>}${R}`
: S;
Replace
Implement Replace<S, From, To>
which replace the string From
with To
once in the given string S
实现 Replace<S, From, To>
将字符串 S
中的第一个子字符串 From
替换为 To
。
type replaced = Replace<'types are fun!', 'fun', 'awesome'> // expected to be 'types are awesome!'
实现:
type Replace<
S extends string,
From extends string,
To extends string
> = From extends ""
? S
: S extends `${infer L}${From}${infer R}`
? `${L}${To}${R}`
: S;
ReplaceAll
Implement ReplaceAll<S, From, To>
which replace the all the substring From
with To
in the given string S
实现 ReplaceAll<S, From, To>
将一个字符串 S
中的所有子字符串 From
替换为 To
。
type replaced = ReplaceAll<'t y p e s', ' ', ''> // 期望是 'types'
实现:
按照之前实现Replace的思路,递归剩余部分的字符串,进行字符替换
type ReplaceAll<
S extends string,
From extends string,
To extends string
> = From extends ""
? S
: S extends `${infer L}${From}${infer R}`
? `${L}${To}${ReplaceAll<R, From, To>}`
: S;