Open4

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

https://github.com/type-challenges/type-challenges/tree/main/questions/00004-easy-pick


Pickについて

Pick<T, Keys>は、型TからKeysに指定したキーだけを含むオブジェクトの型を返すユーティリティ型

https://typescriptbook.jp/reference/type-reuse/utility-types/pick



解答

type MyPick<T, K extends keyof T> = {
  [key in K]: T[key]
}



解説

extends

<T, K extends keyof T>について、extendsは継承ではなく、制約の意味
keyofはオブジェクトの型からプロパティ名を型として返す型演算子

https://zenn.dev/bs_kansai/articles/da0547f3128308


Mapped types

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

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

まさきちまさきち

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.

https://github.com/type-challenges/type-challenges/blob/main/questions/00007-easy-readonly/README.md


解答

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)を取り出す

https://tech-blog-masa7351.netlify.app/mapped_types_lookup_types


  • Lookup Types
    プロパティ名を列挙することで、プロパティの型を取り出せる。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

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'}

https://github.com/type-challenges/type-challenges/blob/main/questions/00011-easy-tuple-to-object/README.md


解答

TupleToObject<typeof T> {
   [P in T]: T
}

type TupleToObject<T extends readonly (keyof any)[]> = {[ P in T[number]] : P}