Closed14

「プログラミングTypeScript」を読む その1

suzuki-navisuzuki-navi
let x = {
  a: 1,
  b: "hello",
}

x = {
  a: 2,
  b: "world",
  c: true, // Object literal may only specify known properties, and 'c' does not exist in type '{ a: number; b: string; }'.
}

上のコードはコンパイルエラーになるのに、なぜ下のコードはOKなのか?

let x = {
  a: 1,
  b: "hello",
}

type Foo = {
  a: number;
  b: string;
  c: boolean;
}

const y: Foo = {
  a: 2,
  b: "world",
  c: true,
}

x = y; // OK
suzuki-navisuzuki-navi

これもOK

let x = {
  a: 1,
  b: "hello",
}

type Foo = {
  a: number;
  b: string;
  c: boolean;
}

x = ({
  a: 2,
  b: "world",
  c: true,
} as Foo);

console.log(x);

わからない。

suzuki-navisuzuki-navi
let a: bigint = 10n;

console.log(a);
tsconfig.json
{
  "compilerOptions": {
    "lib": ["es2015", "dom"],
    "module": "es2015",
    "target": "es2020",
    "strict": true,
  },
}

bigintのリテラルを書くには tsconfig.jsoncompilerOptions.targetes2020 以上にする必要がある。 es2015 などにすると、 BigInt literals are not available when targeting lower than ES2020. というコンパイルエラーが発生する。

suzuki-navisuzuki-navi

もうひとつハマった点、 tsc hello.ts とすると tsconfig.json が反映されないみたい。 tsc になにも引数を付けずに実行すれば tsconfig.json の設定が反映された。

suzuki-navisuzuki-navi

compilerOptions.libes2020 以上を書けば、リテラルでなくても BigInt("10") という表記ができる。

tsconfig.json
{
  "compilerOptions": {
    "lib": ["es2020", "dom"],
    "module": "es2015",
    "target": "es2020",
    "strict": true
  }
}
let a: bigint = BigInt("10");

console.log(a);
suzuki-navisuzuki-navi

配列の型は string[]Array<string> の2通りの書き方がある。意味はまったく同じ。前者はC言語っぽい見た目、後者はScalaっぽい見た目だから、後者のほうが好み。

suzuki-navisuzuki-navi

voidneverがあるのはScalaに似ている。
voidUnitneverNothing

suzuki-navisuzuki-navi

JavaScriptと同じだが、関数の呼び出し方は4つある。

function hello(name: string) {
  console.log(`Hello, ${name}!`);
}

hello("world");
hello.apply(null, ["world"]);
hello.call(null, "world");
hello.bind(null, "world")();

4つとも全部同じ。ただし関数内から参照できる this の取り扱いが異なるらしい。

suzuki-navisuzuki-navi

ジェネレータ

function* hello() {
  let i = 0;
  while (true) {
    yield i++;
  }
}

const generator = hello();
console.log(generator);
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());

出力は

Object [Generator] {}
{ value: 0, done: false }
{ value: 1, done: false }
{ value: 2, done: false }

これもTypeScriptの機能ではなくJavaScriptの話らしい。

suzuki-navisuzuki-navi

ジェネレータの型は Generator<number> のように書く。

function* hello(): Generator<number> {
  let i = 0;
  while (true) {
    yield i++;
  }
}
suzuki-navisuzuki-navi

ジェネレータの実行順序について深堀してみる。

function* hello(): Generator<number> {
  let i = 0;
  while (i < 2) {
    console.log(`before yield ${i}`);
    yield i;
    console.log(`after yield ${i}`);
    i++;
  }
}

const generator = hello();
console.log(generator);
console.log("top level 0");
console.log(generator.next());
console.log("top level 1");
console.log(generator.next());
console.log("top level 2");
console.log(generator.next());
console.log("top level 3");
Object [Generator] {}
top level 0
before yield 0
{ value: 0, done: false }
top level 1
after yield 0
before yield 1
{ value: 1, done: false }
top level 2
after yield 1
{ value: undefined, done: true }
top level 3

やっぱり、最後の要素を取得した時点ではまだ最後かどうかを判定できず、次を取得しようとしたときにはじめてわかる。

suzuki-navisuzuki-navi

関数の型の書き方

type Operator = (x: number, y: number) => number;

const op: Operator = function(x, y) {
    return x + y;
}

console.log(op(1, 2)); // 3
このスクラップは2023/07/15にクローズされました