2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Typescript] 応用

2
Posted at

インターセクション型

A & Bのような型のことを言います。

↓EngineerとBloggerオブジェクトの全てを入れる必要があります。
↓被っているものは1つで良いとみなされるので、nameも1つで大丈夫です。

.ts
type Engineer = {
  name: string;
  role: string;
}

type Blogger = {
  name: string;
  follower: number;
}

type EngineerBlogger = Engineer & Blogger;

const quill: EngineerBlogger = {
  name: 'quill',
  role: 'front-end',
  follower: 1000
}

↓だったら、type Mixはnumber型になります。
↓NumberBooleanとStringNumberで重複しているのがnumberのみだからです。

.ts
type NumberBoolean = number | boolean;
type StringNumber = string | number;
type Mix = NumberBoolean & StringNumber;

Type guard

条件分を使って、型を絞り込んでいく方法です。

typeof

.ts
function toUpperCase(x: string | number) {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return '';
}

in演算子

↓nomadWorkerというオブジェクトにroleキーは存在しますか?という意味になります。
↓存在すればtrueを返します。

.ts
function describeProfile(nomadWorker: NomadWorker) {
  console.log(nomadWorker.name);

  if ('role' in nomadWorker) {
    console.log(nomadWorker.role);
  }
}

instanceof
classの場合使えます。

↓if (pet instanceof Bird)は、「petはBirdのインスタンスですか?」と言っています。
↓Birdクラスから設計されたインスタンスだった場合にtrueを返します。

.ts
class Dog {
  speak() {
    console.log('bow-wow');
  }
}
class Bird {
  speak() {
    console.log('tweet-tweet');
  }
  fly() {
    console.log('flutter');
  }
}

type Pet = Dog | Bird;
function havepet(pet: Pet) {
  pet.speak();
  if (pet instanceof Bird) {
    pet.fly();
  }
}

Tagged union

Type guardのように型を絞り込んでいく、Tagged unionデザインパターンです。

↓DogにもBirdにもkindを置いて、switchに指定して、caseで判別するといった方法です。

.ts
class Dog {
  kind: 'dog' = 'dog'
  speak() {
    console.log('bow-wow');
  }
}
class Bird {
  kind: 'bird' = 'bird'
  speak() {
    console.log('tweet-tweet');
  }
  fly() {
    console.log('flutter');
  }
}

type Pet = Dog | Bird;
function havepet(pet: Pet) {
  pet.speak();
  switch(pet.kind) {
    case 'bird': pet.fly();
  }

Type assertion

手動で型を上書きする方法です。
↓2つとも意味は同じです。
↓document.getElementById('input')を、手動で無理やり「HTMLInputElementです!」と
↓Typescriptに教えてあげています。
↓そうしないとinputがHTMLInputElementかnullかが分からないからです。

.ts
const input = <HTMLInputElement>document.getElementById('input');
.ts
const input = document.getElementById('input') as HTMLInputElement;

Non-null assertion operator

↓末尾についている ! は、絶対にnullじゃないと言い切るものです。

.ts
const input = document.getElementById('input')!;

Index signature

オブジェクトの中身を追加できるというものです。

↓通常オブジェクトに中身を追加できなくて、エラーが起きます。
Image from Gyazo

↓[index: string]: string;という一文を付け加えると、全てOKになります。
↓ただし、[index: string]: string;の最後の型がstringだったら、
↓他のメンバーも全てstring型にしないといけません。(例えばageなど)
Image from Gyazo

↓[index: number]: string;とすると、キーが数値でないとダメになります。
Image from Gyazo

関数のオーバーロード

関数の戻り値を、正しくTypescriptに伝える方法です。

↓最後の行のupperHelloは、明らかにstringのはずなのにstring | numberと認識されています。
↓Typescriptには分からないのです。

.ts
function toUpperCase(x: string | number):string | number {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return x;
}

const upperHello = toUpperCase('Hello');

↓ここで関数のオーバーロードを使います。
↓function toUpperCase(x: string): string;   =  stringの返り値はstringだよー
↓function toUpperCase(x: number): number;  =  numberの返り値はnumberだよー
↓としてあげることで解決します。

.ts
function toUpperCase(x: string): string;
function toUpperCase(x: number): number;

function toUpperCase(x: string | number):string | number {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return x;
}

const upperHello = toUpperCase('Hello');

これがオーバーロードです。

Optional Chaining

Javascriptは、要はundefinedかnullの
メソッドやプロパティに対してアクセスしようとするとエラーが出ます。

そのエラーを防ぐために何かあったらundefinedで止めておくといった書き方です。

.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

const downloadedData: DownloadedData = {
  id: 1
}

console.log(downloadedData.user?.name?.first);

↑downloadedData.user?.nameは、
↑downloadedData.userがundefinedもしくはnullだったら、undefinedを返す、
↑それ以外が入っていたら、nameを返すという意味です。

Nullish Coalescing

↓undefinedとnullの2つだけに対しては'no-user'になるといったようなものを
↓Nullish Coalescingと言います。

.ts
const userData = downloadedData.user ?? 'no-user';

LookUp型

オブジェクトの型の、メンバーが持っている型にアクセスするときに使います。

↓[ ]で指定すると、そのメンバーの型にアクセスできます。
↓type idはnumber型になっています。

.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

type id = DownloadedData['id'];

↓type idは(number | user?)型になっています。

.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

type id = DownloadedData['id' | 'user'];

Typescriptの加算演算表

「Typescriptの型安全性」と「Javascriptの柔軟性」

    |Any  |Boolean |Number |String  |Other

--------|---------|-------|------|--------|------------
Any   | Any | Any | Any | String | Any
Boolean | Any | | | String |
Number | Any | |Number| String |
String | String | String|String| String |String
Other | Any | | | String |

オーバーロードを型で表現する

↓オーバーロードを型で表現する場合は、
↓オーバーロードした全ての関数に対応した関数しか入れれません。

.ts
interface TmpFunc {
  (x: string): number;
  (x: number): number;
}
const upperHello: TmpFunc = function(x: string | number) { return 0 };
//string と numberに対応した型の関数しか使えない

関数型のIntersection

.ts
interface FuncA {
  (a: number, b: string): number;
  (a: string, b: number): number;
}

interface FuncB {
  (a: string): number;
}

let intersectionFunc: FuncA & FuncB;

↑intersectionFunc: FuncA & FuncB;は、
↓のようにオーバーロードされた型になっています。

.ts
  (a: number, b: string): number;
  (a: string, b: number): number;
  (a: string): number;

関数型のUnion型

↓unionFuncは、パラメーターはintersection型になり、戻り値はunion型になります。

.ts
interface FuncA {
  (a: number): number;
}

interface FuncB {
  (a: string): string;
}

let unionFunc: FuncA | FuncB;

Rest Parameter

↓関数advanceFnに、いくつも引数を入れられるよーというものです。
↓.を3つ付けてその後名前を付けます。
↓するとその名前が配列としてadvanceFn使えます。
↓さらに: number[ ]のように、配列の型を付けることでRest Parameterに型付けできます。

.ts
function advanceFn(...args: number[]) {
  args[0];
}
advanceFn(0, 1, 2, 3)

↓Tuple型もつけられます。
↓Optional parameterも付けれます。
↓可変調ではなくなります。

.ts
function advanceFn(...args: [number, string, boolean?]) {
}
advanceFn(0, 'web', true);

↓Tuple型に可変長を付けることもできます。
↓... + 型 + 配列

.ts
function advanceFn(...args: [number, string, boolean, ...number[]]) {
  args[0];
}
advanceFn(0, 'web', true, 0, 1, 2, 3);

配列とTupleにreadonly修飾子を付ける

↓:と配列の間、型のところにreadonlyを付けることができます。

.ts
function advanceFn(...args: readonly [number, string, boolean, ...number[]]) {
}
advanceFn(0, 'web', true, 0, 1, 2, 3);

読み物になるので、args.pushで入れれなくなったりします。

const Assertion

as constと付けると、定数のようになります。

↓milkはstring型です。

.ts
let milk = 'milk';

↓milkはmilkというString literal型になります。

.ts
let milk = 'milk' as const;

↓arrayはnumber[ ]になります。

.ts
const array = [10, 20];

↓readonly [10, 20]という、 readonly + Tuple型になります。

.ts
const array = [10, 20] as const;

↓はconst peter: {
   name: string;
   age: number;
  }
↓となります。

.ts
const peter = {
  name: 'peter',
  age: 38
}

↓はconst peter: {
   readonly name: "peter";
   readonly age: 38;
  }
↓となります。

.ts
const peter = {
  name: 'peter',
  age: 38
} as const;

型の中でtypeofを使う

↓peterの型を代入したいとき、これではダメです。
↓peterは値なので、PeterTypeは成り立ちません。

.ts
const peter = {
  name: 'peter',
  age: 38
} as const;

type PeterType = peter;

↓そんなときpeterの型を取得するにはtypeofをくっ付けます。

.ts
const peter = {
  name: 'peter',
  age: 38
} as const;

type PeterType = typeof peter;
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?