Closed24

TypeScript

これは文なので;がいらない

function f() {
  return 42;
}

これは式なので;がいる

f = function() {
  return 42;
};

( js )

巻き上げ ( js )

動く

f();

function f() {
  return 42;
}

動かない

f();

f = function() {
  return 42;
};

そんな名前があったのか

感覚的にはしっくりくる

関数が値だからプロパティにできるよってはなし

略記もあるらしい

x = {
    id: 1,
    f: function() {
        return `id: ${this.id} ( f )`
    },
    g() {
        return `id: ${this.id} ( g )`
    }
}

console.log(x.f());    // id: 1 ( f )
console.log(x.g());    // id: 1 ( g )

( js )

classobject らしい

プロパティを足せるらしい

class Item {
    constructor(id, name) {
        this.id = id;
        this.name = name;
    }
}

item = new Item(1, 'John');
console.log(item);    // Item { id: 1, name: 'John' }

item.price = 100;
console.log(item);    // Item { id: 1, name: 'John', price: 100 }

ということは、{}を期待しているところに渡せる?

console.log(Object.keys(item));    // [ 'id', 'name', 'price' ]

渡せた

console.log(typeof item);    // object

はぇ

( js )

継承がある

typeof じゃあなくて instanceof というのがある

class Phone {

}

class Android extends Phone {
    constructor() {
        super();
    }
}

android = new Android();

console.log(android instanceof Phone);      // true
console.log(android instanceof Android);    // true

( js )

interfaceabstract とアクセス修飾子はない ( js )

ts にはあるらしい

js で 'foo' はプリミティブな string
なのに 'foo'.length が動くのは String に暗黙変換されているから

java の auto-boxing と同じっぽい

ts-node
$ const s = 'foo';
$ const S = new String('foo');

$ typeof s
'string'
$ typeof S
'object'

$ Object.keys(s)
[eval].ts:5:13 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'.

$ Object.keys(S)
[ '0', '1', '2' ]

stringobject を期待している keys には渡せない

Stringlength があるのかなと思ったけど、インデックスしかなかった

リテラル型

const b: false = false;

console.log(b);

なんこれ
| とかできるん?

できた

const n: 4 | 5 = 4;

console.log(n);           // 4
console.log(typeof n);    // number

なんこれ
こんなこともできるのか

const n: 4 | false = 4;

console.log(n);           // 4
console.log(typeof n);    // number
const n: 4 | false = false;

console.log(n);           // false
console.log(typeof n);    // boolean

number | boolean って型になるわけではないのか

これは通るけど

function f(): number | false {
    return 4;
}

const n = f();

これだと通らない

function f(): number | false {
    return 4;
}

const n: number = f();

any は全ての値を許容して、実行できる
unknown も全ての値を許容するが、実行できない
never は全ての値を代入できない ( 後述? )

tsconfig.jsonnoImplicitAny というパラメータがある

親子関係にないクラスでダウンキャストが行えないので、unknown かなにかを挟むといいらしい
するか?

Nominal TypingStructual Subtyping

型シグネチャが同じならば置換できる

適当に作ったクラスのフィールドとメソッドが同じ場合、置換できてしまう

防ぐにはリテラル型とかを使って name: 'UserId' = UserId みたいにシグネチャをユニークにする

なにそれクソめんどくさ
いらな

何に使うんだろう...

typeof で判定した後はその型に断定できる ( Type Guard )

function f(x: unknown) {
    if (typeof x == 'number')
        console.log(typeof x);
    else if (typeof x == 'string')
        console.log(typeof x);
}

f(5);          // number
f('hello');    // string

いちいちブロックの中でキャストとかしなくて良いからいいな

これでユニオンのリテラル型とかと使うのかな

てかリテラル型、補完効くのかすげぇ

case も補完効いたすげぇ

case 漏れたらどうなるのかと思ったけど、そもそも何も起きないだけなのか

function fetch(n: number): 'ok' | 'error1' | 'error2' {
    if (n == 0)
        return 'ok'
    else if (n == 1)
        return 'error1'
    else
        return 'error2'
}

switch (fetch(1)) {
    case'ok':
        console.log('success')
}

やっぱ undefined になるっぽい

function f(n: number) {
    switch (n) {
        case 1:
            return 'one';
    }
}

const x = f(2);

console.log(x);           // undefined
console.log(typeof x);    // undefined

てか、main.js が追従して変更されていくのおもろい
main.js の方にちゃんと ; ついてるけど、ts って ; いらないん?

...稀に曖昧なパターンで解釈ミスがありそうな感じらしい

ひとりなら書かないかもだけど、複数人でやるなら一律ありにしておいた方が無難そう

と言うことで、; は書くことにする

Type Predicate というので bool を戻す場合に型を断定させられる

自分で作った判定関数でも Type Guard が効く様にできるのか

bool じゃあなくて例外 + asserts で行うと、呼んだ後は断定して扱える

へぇぇぇぇぇ

関数の作り方は js と同じで 3 つっぽい

arrow functions は js では arrow functions にならないんだ?

巻き上げ ( 覚えた! ) も同じ感じっぽい

引数に ? をつけると Optional Parameters になる

function f(x: number, y?: number): number {
    return x + y;
}

console.log(f(1));    // NaN

実際には number | undefined になっている ( エディタからも確認できる ) ので NaN になる

ちなみに N | undefined って型定義にしちゃうと引数を 1 つだけ渡すことができない、なるほど

また undefined にない演算はコンパイルできない... と思ったら実行例外だった...

class N {
    v: number;
    constructor(v) {
        this.v = v;
    }
}

function f(x: N, y?: N): number {
    return x.v + y.v;
}

console.log(f(new N(1)));

素直に条件分岐するか、デフォルト引数を使う

デフォルト引数で良い気がするな?

function f(x: N, y: N = new N(2)): number {
    return x.v + y.v;
}

console.log(f(new N(1), new N(2)));

可変長引数もあるよ

function sum(...ns: number[]): number {
    return ns.reduce((acc, n) => acc - n);
}

console.log(sum(5, 3, 1));    // 1

( sum が見つからなかったので reduce してみた )

スプレッド構文を使うとバラして渡せる

function sum(...ns: number[]): number {
    return ns.reduce((acc, n) => acc - n);
}

const ns = [5, 3, 1];
console.log(sum(...ns));    // 1

分割代入ってのもあるよ

名前付き引数っぽい

type Pair = {
    x: number;
    y: number;
}

function sub({x, y}: Pair): number {
    return x - y;
}

console.log(sub({x: 5, y: 3}));    // 2

同名変数が準備してあれば略記があるっぽい

const x = 6;
const y = 1;

console.log(sub({x, y}));          // 5
このスクラップは2021/11/30にクローズされました
作成者以外のコメントは許可されていません