はじめに
k.s.ロジャースの藤本です。
今まで雰囲気でTypeScriptを書いていて正解がわからなくなることがあるため
改めて基礎から学びなおしてみました。自分の備忘録として残しておきます。
基本の型(プリミティブ型)
基本的に使うのはこの辺り?
- boolean
- number
- string
// let 変数名:型 = 値;
let hoge:string = 'Hello World';
リテラル型
指定した文字列のみ許可
かつ、文字列のリテラル型を持つ値はstringとして扱うことができる
let hoge: 'message' = 'message';
let fuga: string = hoge;
以下のような場合は、エラーとなる
let hoge: 'message' = 'Hello World';
// error TS2322: Type '"Hello World"' is not assignable to type '"message"'.
union型
|
を用いて記述することによりstring型、number型のどちらにも対応するような形で宣言することができる。
let hoge:string | number;
hoge = 'Hello';
hoge = 222; // 数値を代入してもエラーにならない
以下のように使用も可能
let message: 'Hello' | 'World';
message = 'Hello';
message = 'World';
message = '!!'; // Errro: 型 '"!!"' を型 '"Hello" | "World"' に割り当てることはできません。
オブジェクト型
各プロパティに型指定ができる
interface MyInterface {
hoge: string;
fuga: number;
}
const piyo: MyInterface = {
hoge: 'message',
fuga: 100
}
短ければそのまま書くこともできる
const piyo: { hoge: string, fuga: number } = {
hoge: 'message',
fuga: 100
}
?
を付けるとnullableとして宣言できる
interface MyInterface {
hoge: string;
fuga?: number;
}
const piyo: MyInterface = {
hoge: 'message'
}
readonly
を付けると再代入ができなくなる。
interface MyInterface {
readonly hoge: string;
fuga?: number;
}
const piyo: MyInterface = {
hoge: 'message'
}
piyo.hoge = 'Hello';
// error TS2540: Cannot assign to 'hoge' because it is a read-only property.
Class
class Cat {
constructor(name: string, age: number) {
console.log(name, age);
}
}
new Cat('Tama', 5);
ちなみにトランスパイル後はこうなっていました。
var Cat = /** @class */ (function () {
function Cat(name, age) {
console.log(name, age);
}
return Cat;
}());
new Cat('Tama', 5);
外部Module
export const HOGE = "hoge";
const FUGA = "fuga";
import { HOGE } from "./util";
import { FUGA } from "./util"; // error
// エクスポートされたメンバー 'FUGA' がありません
console.log(HOGE); // 'hoge'が出力される
内部Module
namespace exampleA {
export let hoge:string;
let fuga:string;
}
namespace exampleB {
export let hoge:string;
}
exampleA.hoge = "Hello";
exampleA.fuga = "Hello"; // 参照できないためerror
exampleB.hoge = "World";
console.log(exampleA.hoge);
console.log(exampleB.hoge);
enum
enum Fruit {
apple = 10,
grape = 20,
lemon = 30
}
console.log(Fruit.apple, Fruit.grape, Fruit.lemon);
// 10 20 30が表示される
Symbol
シンボルは不変で一意となる。
let hoge = Symbol("key");
let fuga = Symbol("key");
console.log(hoge === fuga); // 結果: false
色んな面で便利に使えるとは思いますが
今回は簡単な例としてユニークのキーを作るのに使用します。
以下、非常に悪い例です。
let key = 'key_' + Math.random();
hoge[key] = true;
こんな作り方はまずしないと思いますが・・・。
上記だと100%ユニークではないので、もっと正しく書くのであれば
keyの重複チェックが必要となり結果これよりは長くなります。
let key = Symbol("key");
hoge[key] = true;
こう書けば確実にユニークになり、かつ可読性も良いので便利そう
Generics
まずGenericsを使わない例として、以下のように
渡した文字をただ返すだけの関数の型を見てみます。
const returnString = (x: string): string => x;
const returnNumber = (x: number): number => x;
console.log(typeof(returnString('10')));
console.log(typeof(returnNumber(10)));
// 結果: string number
内部処理は一緒なのに、型が違うだけで関数を二つ用意しなければいけません。
Genericsを利用すると以下のように書くことができます。
const returnGenerics = <T>(x: T): T => x
console.log(typeof(returnGenerics<string>('10')));
console.log(typeof(returnGenerics<number>(10)));
console.log(typeof(returnGenerics<boolean>(false)));
// 結果: string number boolean
Classに使用することも可能です。
class testGenerics<T> {
private value: T;
constructor(value:T) {
this.value = value;
}
public getValue():T {
return this.value;
}
}
let outputString = new testGenerics<string>('hoge');
let outputNumber = new testGenerics<number>(10);
let outputBooleang = new testGenerics<boolean>(false);
console.log(outputString.getValue(), outputNumber.getValue(), outputBooleang.getValue());
// 結果: hoge 10 false
console.log(typeof(outputString.getValue()));
console.log(typeof(outputNumber.getValue()));
console.log(typeof(outputBooleang.getValue()));
// 結果: string number boolean
終わり
もっともっと基礎的な部分はあると思いますが
とりあえずはこんなところにしておきます。
「これは最初のうちに覚えたほうがいいよ!」
というのがあれば是非、ご教授頂けますとうれしいですmm
Wantedlyでもブログ投稿してます
Techブログに加えて会社ブログなどもやっているので、気になった方はぜひ覗いてみてください。
https://www.wantedly.com/companies/ks-rogers