Type-Challangeに挑戦する
Type-Challange
1. Type-Challange: Pick
Implement the built-in Pick<T, K> generic without using it.
Constructs a type by picking the set of properties K from T
Pickについて
Pick<T, Keys>は、型TからKeysに指定したキーだけを含むオブジェクトの型を返すユーティリティ型
解答
type MyPick<T, K extends keyof T> = {
[key in K]: T[key]
}
解説
extends
<T, K extends keyof T>
について、extendsは継承ではなく、制約の意味
keyof
はオブジェクトの型からプロパティ名を型として返す型演算子
Mapped types
{ [ P in K ] : T } の表記で型を動的に作り出すことが可能。
keyof で型からプロパティ名(Key)を取り出して、in により順次処理 Type[key] 型からプロパティ型
type Item = { a: string, b: number, c: boolean };
type T1 = { [P in "x" | "y"]: number }; // { x: number, y: number }
type T2 = { [P in "x" | "y"]: P }; // { x: "x", y: "y" }
type T3 = { [P in "a" | "b"]: Item[P] }; // { a: string, b: number }
type T4 = { [P in keyof Item]: Date }; // { a: Date, b: Date, c: Date }
type T5 = { [P in keyof Item]: Item[P] }; // { a: string, b: number, c: boolean }
type T6 = { readonly [P in keyof Item]: Item[P] }; // { readonly a: string, readonly b: number, readonly c: boolean }
type T7 = { [P in keyof Item]: Array<Item[P]> }; // { a: string[], b: number[], c: boolean[] }
https://tech-blog-masa7351.netlify.app/mapped_types_lookup_types]
keyof and Lookup Types
type P1 = Person["name"]; // string
2. Readonly
Implement the built-in Readonly<T> generic without using it.
Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.
解答
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
解説
type User = {
id: number;
name: string;
points: number;
};
type MakeReadOnly<Type> = {readonly [key in keyof Type ]: Type[key]};
// Test MakeReadOnly
type ReadOnlyUser = MakeReadOnly<User>;
/* Result
type ReadOnlyUser = {
readonly id: number;
readonly name: string;
readonly points: number;
}
*/
まずは、Mapped Typesの{ [ P in K ] : T } の表記で型を動的に生成する。
次に、keyof で型からプロパティ名(Key)を取り出して、in により順次処理 Type[key] 型からプロパティ型(number , string)を取り出す
- Lookup Types
プロパティ名を列挙することで、プロパティの型を取り出せる。
interface Person {
name: string;
age: number;
location: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string
type UserKeyTypes = User[keyof Person];
// type UserKeyTypes = number | string;
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key]; // Inferred type is T[K]
}
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
obj[key] = value;
}
let x = { foo: 10, bar: "hello!" };
let foo = getProperty(x, "foo"); // number
let bar = getProperty(x, "bar"); // string
3. Tuple to Object
Given an array, transform it into an object type and the key/value must be in the provided array.
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type result = TupleToObject<typeof tuple> // expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
解答
TupleToObject<typeof T> {
[P in T]: T
}
type TupleToObject<T extends readonly (keyof any)[]> = {[ P in T[number]] : P}