Closed10

Reading: TypeScript Official Handbook

bufferingsbufferings

ぼーっとメモ

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html

Basics

  • string

  • number

  • boolean

  • string[]

  • number[]

  • any

  • 変数

    • あんまり型を書くことなさそう。infer してくれるから
  • 関数

    • パラメーターの型は書きそう
    • 戻り値の型は書かなくても良さそう
  • あぁでも、array.map みたいなのに渡す anonymous function の場合はパラメーターの型は分かるから書かなくても良いのか

Object Types

function printCoord(pt: { x: number; y: number }) {

区切りは ; でも , でもいいって。へー。

Optional

function printName(obj: { first: string; last?: string }) {

Type と Interface

type と interface はどっちが良いんだろうなぁ?個人的には type が好きだけど。
公式だと interface 推し。たしか前に読んだ本は type 推しだったっけな。

Type Assertions

へー

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

使うなら前者かな

Literal Types

面白いよねこれ

Literal Interface

method を "GET" 固定にしたい場合

// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };

// Change 2
handleRequest(req.url, req.method as "GET");

// Change 3
const req = { url: "https://example.com", method: "GET" } as const;

Others

  • Enum はあんまり使わない方が良いって聞いたことある
  • bigint
  • symbol
bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/narrowing.html

type guards

  • "string"
  • "number"
  • "bigint"
  • "boolean"
  • "symbol"
  • "undefined"
  • "object"
  • "function"

typeof null"object" なので注意

type predicates

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

pet as FishpetFish 型とみなして、swim が定義されてる場合は、Fish そうじゃない場合は Bird となる。

pet is Fish の部分で、TypeScript に対して「戻り値が true だったら petFish だよ」って伝えてるっぽいな。false なら Bird ってのも型から判別してしまう。かしこい。

Exhaustiveness checking

こないはず、みたいなチェックが型レベルでできるのかー。面白いな。

type Shape = Circle | Square;
 
function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

この ShapeTriangle みたいなのを足すと、コンパイルエラーになる。

bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/functions.html

// Shorthand call signature
type Log = (a: string) => void

// Full call signature
type Log = {
    (a: string): void
}

パラメーター名は必要

(string) => void

こうしてしまうと string というパラメーター名で型が any という意味になっちゃう

Construct Signatures

type SomeConstructor = {
  new (s: string): SomeObject;
};

Date みたいに、new つけるやつとつけないやつがある場合はこんな風に書ける

interface CallOrConstruct {
  new (s: string): Date;
  (n?: number): number;
}

Generic Functions

function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

Constraints

function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a;
  } else {
    return b;
  }
}

Overload Signatures

JS にはオーバーロードはないけど、引数に色んなパターンで渡せるから TS ではこういう書き方ができる

function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}

好きじゃない。別の関数にしてくれたらいいのに。ライブラリを使うときに読むことはあっても、自分で書くことはなさそうかな。

this もそう。

Other Types to Know About

object

  • objectObject は違う。Object は使わない。object を使う。

unknown

  • unknownany に似てるけど、型を明確にしてからじゃないと使えないので良い
  • 戻り値の型が決められない場合も使える
function safeParse(s: string): unknown {
  return JSON.parse(s);
}

でも、戻り値は気をつけて使う

never

  • 例外や exit で、関数から決して値が返されない場合に指定できる
  • あとは、Exhaustive な場合にも使われる
function fn(x: string | number) {
  if (typeof x === "string") {
    // do something
  } else if (typeof x === "number") {
    // do something else
  } else {
    x; // has type 'never'!
  }
}

Function

  • 使わない

なんでもいいけど自分でコールしない場合は () => void をつけとく

Rest Parameters

配列で定義すればいい

function multiply(n: number, ...m: number[]) {
  return m.map((x) => n * x);
}

Argument でタプル的に展開して使うときは as const してあげたらいい

// Inferred as 2-length tuple
const args = [8, 5] as const;
// OK
const angle = Math.atan2(...args);

Parameter Destructuring

こうなる

function sum({ a, b, c }: { a: number; b: number; c: number }) {
  console.log(a + b + c);
}

Return type void

戻り値の型が void の場合は、何でも返せる

type voidFunc = () => void;
const f1: voidFunc = () => {
  return true;
};

ただ、戻り値を使わないよということ

実際は戻り値があるんだけど、それを期待していない場合のために使われる

Array.prototype.push は数値を返すけど Array.prototype.forEach は使わないので void を期待してる

でも、関数宣言や関数式に書いてる場合はだめ

function f2(): void {
  // これはエラーになる
  return true;
}
bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/objects.html

readonly Properties

readonly のこと忘れてた

interface SomeType {
  readonly prop: string;
}

あんまり使わなさそうかなぁとは思う

Index Signatures

interface StringArray {
  [index: number]: string;
}

index の type には numberstring が使える。んーけどあんまり string は使わなさそうかなぁ。

あとはさらっと

  • Interface の継承
  • Intersection
  • Generics
  • Array<T>, Map<K, V>, Set<T>, Promise<T>
  • ReadonlyArray<string>readonly string[] と同じ
  • タプルは [string, number] みたいに定義できる
bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/generics.html

関数宣言のとこだと

function identity<Type>(arg: Type): Type {
  return arg;
}

関数式のとこだと

let myIdentity: <Type>(arg: Type) => Type = identity;

とか

let myIdentity: { <Type>(arg: Type): Type } = identity;

って書ける

インターフェース

インターフェースはこうなる

interface GenericIdentityFn {
  <Type>(arg: Type): Type;
}
 
function identity<Type>(arg: Type): Type {
  return arg;
}
 
let myIdentity: GenericIdentityFn = identity;

こんな風にも使える

interface GenericIdentityFn<Type> {
  (arg: Type): Type;
}
 
function identity<Type>(arg: Type): Type {
  return arg;
}
 
let myIdentity: GenericIdentityFn<number> = identity;

そしたら number 型が適用された関数になる

Class

クラスでも使える

class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}
 
let myGenericNumber = new GenericNumber<number>();

インスタンスサイドとスタティックサイドのうち、インスタンスサイドにしか効かないので、スタティックなメンバーには型パラメーターは使えない

Generic Constraints

制約はこんな感じ

interface Lengthwise {
  length: number;
}
 
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}

インターフェース使わずにこうでもいける

function loggingIdentity<Type extends {length: number}>(arg: Type): Type {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}

Using Type Parameters in Generic Constraints

へー。自分で使うことはなさそうかなぁ

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}
 
let x = { a: 1, b: 2, c: 3, d: 4 };
 
getProperty(x, "a");
getProperty(x, "m"); // Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.ts(2345

Using Class Types in Generics

これも、とりあえず最初のうちは使うこともなさそう。インスタンス化したいなぁって思うときがあれば見直すくらいで

function create<Type>(c: { new (): Type }): Type {
  return new c();
}
bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/keyof-types.html

keyof ってのがあるよって覚えとくくらいでいっか

https://www.typescriptlang.org/docs/handbook/2/typeof-types.html

JS の typeof の拡張

↓面白い。f は型じゃなくて値だから、それから型を取り出すのに typeof を使ってる

https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html

使わないだろうと思うけど

type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];

これで Agenumber 型になる

type I1 = Person["age" | "name"];

こうすると number | string 型になる

https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

これも使わなさそう

type Example1 = Dog extends Animal ? number : string;

https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

Type のキーを使って違う Type を作るっぽい。

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

使わなさそうかなぁ

https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

面白いなー

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
 
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// type AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"

あんまり使うことなさそうだけど、使うときはドキュメント見ながら、確認しながらだろうな。

bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/classes.html

Fields

フィールドは js だとコンストラクターで this にひっつけたらいいけど、ts だと class の中で宣言しないといけないのかーほほー

フィールドはコンストラクター自体の中で初期化されてないといけない。コンストラクターから呼び出されているメソッドまでは ts は見に行かない

コンストラクターで初期化しない場合は ! をつけとけば未初期化エラーがでない

class OKGreeter {
  // Not initialized, but no error
  name!: string;
}

readonly 修飾子をつけると読み取り専用になる

class Greeter {
  readonly name: string = "world";

フィールドにアクセスするときには this が必須

Interface

実装したメソッドでもパラメーターの型は指定してあげないといけない

また、オプショナルなプロパティは実装先では生成されない

Extends

継承のところは普通のことが書いてあるなぁ

Visibility

デフォルトは public だから書かなくていい。理解のしやすさなどのために書いても良い。

public protected private がある。ちょっと動作が Java とは違いそうだけど、そこまで使わなさそうなので使うときにまたチェックしよう。

TypeScript の private 修飾子と、JavaScript のプライベートフィールド(#)を頭の中で区別して把握しとこ。# は ES2022 で入るのかな?たぶん

Static Members

これもほぼ Java と同じかな

ただ、Static なメンバーはコンストラクター関数にひっつくので Function にビルトインでついてるメンバーは使わない/使えない(name, length, call など)

static block もある

this

JS の this はコンテキストによって変わるからめんどくさそう

基本的には「this が変わるような使い方をしない」で良さそうだけど、もしどうしても気にしないといけないなら、Arrow Function 使っとくといいのかなー。super が使えないみたいだけど

Parameter Properties

へー。コンストラクターのパラメーターに修飾子をつけると、フィールドにしてくれる TS の機能

class Params {
  constructor(
    public readonly x: number,
    protected y: number,
    private z: number
  ) {
    // No body necessary
  }
}
const a = new Params(1, 2, 3);

これで、フィールド x y z がそれぞれの修飾子付きのフィールドになる

素直にフィールドを定義してあげたほうが読みやすそうだと思うけどなー

Class Expressions

クラス式もある

Abstract

Abscract 修飾子もある

クラスはこんなとこか

bufferingsbufferings

https://www.typescriptlang.org/docs/handbook/2/modules.html

ハンドブックはこれで最後だな

TypeScript Specific ES Module Syntax

JS のモジュールに対して TS が追加してる機能

export type

typeinterfaceexport できる

import type

import typetypeinterface などの型を import できる

import typeimport したものを値として使おうとするとコンパイルエラーになる:

インラインでも書ける

import { createCatName, type Cat, type Dog } from "./animal.js";
このスクラップは2021/10/13にクローズされました