"CPVUNF
w ݟ༸ีBLB!2VSBNZ
w ϑϩϯτΤϯυΤϯδχΞ
w ීஈ3FBDU3FEVY ͱ'MPX
Ͱ8FCΞϓϦॻ͍ͯ·͢
Slide 3
Slide 3 text
ͱ5ZQF4DSJQU
w ͱͱ"OHVMBS͕͖
w ݄ʹ(PPHMF͕ʮ"OHVMBSY5ZQF4DSJQUʹ͢
ΔΘʔʯͱએݴͨ͠λΠϛϯάͰ5ZQF4DSJQUʹڵຯΛ࣋ͭ
w Ͱ7JNͰॻ͖͔ͨͬͨͷͰɺQMVHJOͭ͘Δ
IUUQTHJUIVCDPN2VSBNZUTVRVZPNJ
w ࣄͰUTॻ͖ͨ͘ͳͬͯϑϩϯτʹδϣϒνΣϯ
5ZQF4DSJQUͱ
w IUUQTXXXUZQFTDSJQUMBOHPSH
w .JDSPTPGU͕։ൃͨ͠"MU+BWB4DSJQU
ओཁͳઃܭऀʹ"OEFST)FKMTCFSH͕͍Δ
w ੩తͳܕݴޠ
w #PPUTUSBQQJOH
w ΤσΟλϑϨϯυϦʔ
Slide 8
Slide 8 text
ܕνΣοΫͱਪ
w ؔTVNͷΓOVNCFSͰ͋Δ͜ͱΛਪ͢Δ
function sum(a: number, b: number) {
return a + b;
}
console.log(sum(1, sum(1, 1))); // OK
// Argument of type '"a"' is not assignable to
// parameter of type 'number'
console.log(sum('a', 'b'));
Slide 9
Slide 9 text
4USVDUVBM4VCUZQJOH
w 5ZQF4DSJQUߏత෦ܕΛ࠾༻͍ͯ͠Δ
w %VDL5ZQJOHͷܕόʔδϣϯͷΑ͏ͳͷ
w ܕͷܧঝؔؾʹͤͣɺܕ͕͍ͬͯΔϝιουɾϓϩ
ύςΟͷ߹கͷΈΛؾʹ͢Δ
Slide 10
Slide 10 text
4USVDUVBM4VCUZQJOH
class Hoge {
name = "Kurami";
}
class Foo {
name = "Quramy";
}
function sayHello(obj: { name: string }) {
console.log(obj.name);
}
sayHello(new Hoge());
sayHello(new Foo());
sayHello(new Error("error"));
Slide 11
Slide 11 text
༨ஊ
/PNJOBMʹ͍ͨ͠ͱ͖
w ͨ·ʹߏత෦ܕͩͱࠔΔ͜ͱ͕͋Δ
w QSJWBUFϑΟʔϧυΛ͏ϋοΫͰճආ͢Δ
class DateISOString {
private _ = Symbol("DateISOString");
readonly isoString = new Date().toISOString();
}
function hoge(x: DateISOString) {
console.log(x.isoString);
}
hoge(new DateISOString());
hoge({ isoString: "hoge" }); // Error
Slide 12
Slide 12 text
4USJDUDIFDL
w TUSJDUΦϓγϣϯʢσϑΥϧτͰPOʣΛ͚͓ͯ͘ͱɺݎ
࿚ͳνΣοΫ͕Մೳʹ
function hoge(x?: string) {
//Object is possibly 'undefined'.
return x.trim();
}
function hoge(x?: string) {
if (!x) return "";
return x.trim(); // OK
}
Slide 13
Slide 13 text
BMMPXKTDIFDLKT
w ৽͘͠ϓϩδΣΫτΛ࡞Δͱ͖ɺTUSJDUͰΑ͍
w Ұํɺطଘͷ+BWB4DSJQUϓϩδΣΫτʹ5ZQF4DSJQUΛಋೖ
͢Δ͜ͱՄೳ
w BMMPXKTDIFDLKTΦϓγϣϯΛPOʹ͢ΔͱɺUT͚ͩͰ
ͳ͘ɺKTϑΝΠϧΛѻ͏͜ͱͰ͖ΔͷͰɺগͣͭ͠UT
ஔ͖͑Δ͜ͱ͕Ͱ͖Δ
Slide 14
Slide 14 text
ϥΠϒϥϦͷܕఆٛ
w ༗໊ͳϥΠϒϥϦOQNJ!UZQFϥΠϒϥϦ໊Ͱܕఆٛ
͕ެ։͞Ε͍ͯΔ
npm i @types/node
import path from "path";
export function hoge() {
const x = path.join("src", "main.ts");
}
Slide 15
Slide 15 text
!UZQFT
w IUUQTHJUIVCDPN%FpOJUFMZ5ZQFE%FpOJUFMZ5ZQFE
Slide 16
Slide 16 text
3FMFBTFDZDMF
w ϲ݄पظͰϚΠφʔόʔδϣϯ͕VQEBUF͞Ε͍ͯ͘
w ηϚϯςΟοΫόʔδϣϯχϯάͰͳ͍
w ͷΑ͏ͳNJOPSVQEBUFͰ͋ͬͯɺഁյతม
ߋ͕ՃΘΔ͜ͱ͋Δ
w CMPHͰഁյతมߋʹ͍ͭͯΞφϯε͕͋ΔͷͰɺͦΕΛ
ΑΜͰ͔ΒVQEBUF͢ΔͱΑ͍
Slide 17
Slide 17 text
#SFBLJOH$IBOHFT
Slide 18
Slide 18 text
5$ͱͷ݉Ͷ߹͍
w جຊతʹ5$ͰTUBHFʹͳ༷͕ͬͨऔΓࠐ·ΕΔ
w ྫ
w /VNFSJD4FQBSBUPS
w #JH*OU
const i = 60_000;
Slide 19
Slide 19 text
͍͔ͭ͘ͷྫ֎
w FYQFSJNFOUBM%FDPSBUPS
FNJU%FDPSBUPS.FUBEBUB
w WY͔Βར༻Մೳɻ"OHVMBS͜Ε͕ͳ͍ͱΓཱͨ
ͳ͍
w KTYSFBDU
w WY͔Βར༻ՄೳɻΈΜͳେ͖+49
Slide 20
Slide 20 text
͜͜ͷ৽ػೳ
$PNQJMFSฤ
Slide 21
Slide 21 text
$PNQJMFS
Slide 22
Slide 22 text
FT.PEVMF*OUFSPQ
Slide 23
Slide 23 text
FT.PEVMFT*OUFSPQ
w Նࠒʹ/PEFKTͷ&4.PEVMFTʹ͍ͭͯͷऔѻʹಈ
͖͕͋ͬͨͷΛड͚ͯɺWYͰಋೖ͞ΕͨΦϓγϣϯ
w ৄ͘͠IUUQTUFQQFJTIBUFOBCMPHDPNFOUSZ
FTNPEVMFTJOOPEFKTͳͲΛࢀর
w &4.PEVMFT͔Β$PNNPO+4NPEVMFΛJNQPSU͢Δࡍ
EFGBVMUJNQPSUΛΘͶͳΒͳ͍
Slide 24
Slide 24 text
FT.PEVMFT*OUFSPQ
w /PEFKTͰɺ$PNNPO+4͔ΒOBNFEJNQPSU͢ΔͱΤ
ϥʔʹ
/* hoge.mjs */
import { readFile } from "fs";
$ node --experimental-modules hoge.mjs
SyntaxError: The requested module does not provide an export
named ‘readFile'
at checkComplete (internal/loader/ModuleJob.js:75:27)
at moduleJob.linked.then (internal/loader/ModuleJob.js:
58:11)
at
Slide 25
Slide 25 text
FT.PEVMFT*OUFSPQ
w Ұํɺ5ZQF4DSJQUͰඇ&4.PEVMFT͔ΒͷEFGBVMU
JNQPSUར༻Ͱ͖ͳ͔ͬͨͨΊɺ$PNNPO+4ΛJNQPSU͢
ΔʹɺOBNFEJNQPSUͰهड़͢Δ͔͠ͳ͔ͬͨ
import * as fs from "fs";
import { readFile } from "fs";
Slide 26
Slide 26 text
FT.PEVMFT*OUFSPQ
w WYҎ߱Ͱɺ$PNNPO+4͔ΒͷEFGBVMUJNQPSU͕ڐ༰͞
ΕΔΑ͏ʹͳͬͨ
w ैདྷͷOBNFEJNQPSUͷॻ͖ํґવڐ༰͞Ε͍ͯΔͷ
ͷɺ5ZQF4DSJQUެࣜʹEFGBVMUJNQPSUͷॻ͖ํΛਪͯ͠
͍Δɻ
IUUQTXXXUZQFTDSJQUMBOHPSHEPDTIBOECPPLSFMFBTF
OPUFTUZQFTDSJQUIUNMTVQQPSUGPSJNQPSUEGSPN
DKTGPSNDPNNPOKTNPEVMFTXJUIFTNPEVMFJOUFSPQ
import fs from "fs";
Slide 27
Slide 27 text
*NQSPWF.BQQFE
5ZQF.PEJpFS
Slide 28
Slide 28 text
.BQQFE5ZQF.PEJpFS
w WYͰಋೖ
w ैདྷͷ.BQQFE5ZQFͰɺSFBEPOMZ Λ༩͢Δ͜ͱ
Ͱ͖ͯɺղআ͢Δ͜ͱͰ͖ͳ͔ͬͨ
type Optional = {
[P in keyof T]?: T[P]
};
type ReadOnly = {
readonly [P in keyof T]: T[P]
};
Slide 29
Slide 29 text
XJUINPEJpFS
w ͷ༩Ͱɺ࡞༻ͷ͖ ͚Δ֎͢
ΛදݱՄೳʹ
type Optional = {
[P in keyof T]+?: T[P]
};
type Strict = {
[P in keyof T]-?: T[P]
};
type ReadOnly = {
+readonly [P in keyof T]: T[P]
};
type Mutable = {
-readonly [P in keyof T]: T[P]
};
Slide 30
Slide 30 text
XJUINPEJpFS
type Strict = {
[P in keyof T]-?: T[P]
};
// Property 'name' is missing in type '{}'
// but required in type 'Strict<{ name?: string |
undefined; }>'.
const x: Strict<{ name?: string }> = { };
Slide 31
Slide 31 text
$POEJUJPOBMUZQFT
Slide 32
Slide 32 text
$POEJUJPOBMUZQFT
w WYͰಋೖ
w "TTJHOBCMFΛ݅ͱͯ͠ذ͢ΔܕΛදݱՄೳ
w ʮܕ5͕ܕ6ͷ෦ܕͰ͋Εɺܕ9ɺͦ͏Ͱͳ͚Εܕ:ʯ
ͱ͍͏ҙຯ
type MyType = T extends U ? X : Y;
Slide 33
Slide 33 text
-FUTUZQF
w ༡ΜͰΈΑ͏$POEJUJPOBM5ZQFT
w %J⒎
w %J⒎ͲΜͳܕͰ͠ΐ͏͔ʁ
type DiffKey = K1 extends K2 ? never : K1;
type $Diff = {
[P in DiffKey]: T[P];
};
Slide 34
Slide 34 text
%JTUSJCVUJPO
w $POEJUJPOBM5ZQFTͱ6OJPO5ZQFTͷؒʹཱ͕
w OFWFS͍͔ͳΔܕʹೖෆՄೳͳܕʢϘτϜܕʣ
w
type DiffKey = K1 extends K2 ? never : K1;
let key: DiffKey<("name" | "age"), "age">;
// ("name" extends "age" ? never : "name")
// | ("age" extends "age" ? never : "age")
// = ("name" | never)
// = "name"
Slide 35
Slide 35 text
$POEJUJPOJONBQQFEUZQFT
w %J⒎,FZLFZPG5
LFZPG6ʮܕ5ͷLFZશମ͔Βɺܕ6
ͷLFZશମͷू߹ΛҾ͍ͨू߹ʯ
w .BQQFE5ZQF͋ΔLFZͷू߹ʹର͢ΔϓϩύςΟͷϚο
ϐϯά
type $Diff = {
[P in DiffKey]: T[P];
};
Slide 36
Slide 36 text
%J⒎ͷਖ਼ମ
w 'MPXUZQFʹಉ໊ͷ6UJMJUZUZQF͕͋Γ·͢
type DiffKey = K1 extends K2 ? never : K1;
type $Diff = {
[P in DiffKey]: T[P];
};
const defaultProps = { age: 0 };
let requiredProps: $Diff<{
name: string;
age: number;
}, typeof defaultProps>;
requiredProps = { name: "Quramy" };
Slide 37
Slide 37 text
5ZQFJOGFSFODFJO
DPOEJUJPOBMUZQFT
Slide 38
Slide 38 text
5ZQFJOGFSFODFJO
DPOEJUJPOBMUZQFT
w WYͰ$POEJUJPOBM5ZQFTͱಉ࣌ʹϦϦʔε͞Εͨػೳ
w $POEJUJPOBM5ZQFTͷ݅෦ʹͯϚονϯά࣌ʹਪ͞
ΕͨܕΛ࠶ར༻Ͱ͖ΔΑ͏ʹ
T extends MyCondition ? SomeType : Y;
Slide 39
Slide 39 text
*OGFSBOE$BQUVSF
w ਖ਼نදݱͷΩϟϓνϟϦϯάʢάϧʔϓԽʣͱࣅ͍ͯΔ
w Ϛονͨ͠άϧʔϓ෦Λޙ͔Βར༻Ͱ͖Δ
const regexp = /hoge(\d+)/;
const hit = "hoge10".match(regexp);
console.log(hit[1]) // 10
Slide 40
Slide 40 text
*OGFSBOE$BQUVSF
w 5͕ؔͰ͋ΕɺͦͷΓͱͯ͠ਪ͞ΕΔܕ͕3ʹ֨
ೲ͞ΕΔ
type Return =
T extends (...args: any[]) => infer R ? R : never;
let r: Return<() => number>; // typeof r = number
Slide 41
Slide 41 text
3FEVYͬΆ͍ΞϨ
type Return =
T extends (...args: any[]) => infer R ? R : never;
type AppState = { [P in keyof T]: Return };
const reducers = {
name: (state: string, action: any) => state,
age: (state: number, action: any) => state,
};
let appState: AppState;
// typeof appState = { name: sting, age: number }
Slide 42
Slide 42 text
͍͗͢ʹҙ
w $POEJUJPOBM5ZQFTͱ5ZQF*OGFSFODF SZʹΑͬͯɺطଘ
ͷܕఆ͔ٛΒ৽͘͠ܕΛ࡞Δखஈ͕֨ஈʹ্
w ॻ͍ͯΔͱ͖ύζϧײ֮Ͱָ͍͠ͷͷɺదͳ༻๏ɾ
༰ྔΛ৺͕͚ͨ΄͏͕Α͍
w Τϥʔϝοηʔδ͕ͲΜͲΜಡΈͮΒ͘ͳΔ
w ϨϏϡΞ͕ͨ·ͬͨΜ͡Όͳ͍
Slide 43
Slide 43 text
VOLOPXO
Slide 44
Slide 44 text
VOLOPXOUZQF
w WYͰಋೖ
w VOLOPXOͯ͢ͷܕ͕BTTJHOBCMF
w VOLOPXOUZQFɺUZQFBTTFSUJPO͠ͳ͍ͱԿͰ͖ͳ͍
function hoge(x: unknown) {
if (typeof x === "string") {
console.log(x.toLowerCase());
}
}
hoge(10);
hoge("foo");
Slide 45
Slide 45 text
5VQMFTJOSFTUQBSBNFUFST
BOETQSFBEFYQSFTTJPOT
Slide 46
Slide 46 text
5VQMFTJOSFTUQBSBNFUFST
BOETQSFBEFYQSFTTJPOT
w WYͰɺؔҾʹؔ͢Δܕͷهड़ྗ͕ڧԽ͞Εͨ
w 3FTUQBSBNFUFSTXJUIUVQMFUZQFT
w 4QSFBEFYQSFTTJPOTXJUIUVQMFUZQFT
w (FOFSJDSFTUQBSBNFUFST
w 0QUJPOBMFMFNFOUTJOUVQMFUZQFT
w 3FTUFMFNFOUTJOUVQMFUZQFT
Slide 47
Slide 47 text
3FTUQBSBNFUFSTXJUI
UVQMFUZQFT
w WYҎલ3FTU1BSBNFUFS"SSBZUZQFͷΈ͕ڐ༰
w WY͔Β5VQMFUZQFར༻Մೳʹ
function hoge(...args: any[]) {
const a1 = args[0];
const a2 = args[1];
const a3 = args[2];
}
function foo(...args: [string, number]) {
const a0 = args[0]; // string
const a1 = args[1]; // number
const a2 = args[2]; // error
}
Slide 48
Slide 48 text
4QSFBEFYQSFTTJPOTXJUI
UVQMFUZQFT
w 4QSFBE0QFSBUPSʹΑΔؔݺͼग़͠ʹରԠ
ҎલDPNQJMFFSSPSʹͳͬͯ͠·͍ͬͯͨ
w WY͔Β5VQMFUZQFར༻Մೳʹ
declare function foo(a: number, b: number): void;
const args1 = [1, 2] as [number, number];
foo(...args1);
const args2 = [1, "bar" ] as [number, string];
// Argument of type 'string' is not assignable to
// parameter of type 'number'.
foo(...args2);
Slide 49
Slide 49 text
(FOFSJDSFTUQBSBNFUFST
w 3FTU1BSBNFUFSTʹ૯শܕ͕ར༻Մೳʹ
w +BWB4DSJQUGVODUJPOͷCJOEDBMMBQQMZͱͷੑ্
ޙड़ͷTUSJDU#JOE$BMM"QQMZͷૅ
declare function curry(
fn: (x: T, ...args: U) => R
): (x: T) => (...args: U) => R;
const sum = (a: number, b: number) => a + b;
const bound = curry(sum)(1);
const x = bound(2); // type of x = number
const error = bound("hoge"); // error
Slide 50
Slide 50 text
0QUJPOBMFMFNFOUTJOUVQMF
UZQFT
w 5VQMF5ZQFͷதͰ NPEJpFS͕ར༻Մೳʹ
w 3FTU1BSBNFUFSTΛ5VQMF5ZQFͰड͚ΕΔΑ͏ͳͬͨ͜
ͱʹΑΔ෭࢈
type Tuple = [number, string?];
const x1: Tuple = [1];
const x2: Tuple = [1, "foo"];
Slide 51
Slide 51 text
3FTUFMFNFOUTJOUVQMF
UZQFT
w 5VQMF5ZQFதʹ3FTUͳUZQFΛදݱͰ͖ΔΑ͏ʹͳͬͨ
w ؔͷ3FTU1BSBNFUFSTͱͯ͠ར༻Մೳ
function hoge(...args: T) {
return args;
}
const arr = [1, 2, 3];
const v = hoge("hoge", ...arr);
// typeof v = [string, ...number[]]
type Hoge = [string, ...number[]];
Slide 52
Slide 52 text
.BQQFEUVQMFUZQFT
Slide 53
Slide 53 text
.BQQFEUVQMFUZQFT
w WYͰಋೖ
w WY·Ͱ.BQQFE5ZQFʹ"SSBZ-JLFͳ5ZQFΛ৯Θͤ
ͯɺ΄΅ҙຯͷͳ͍݁Ռʹͳ͍ͬͯͨ
w WY͔Βʮྻཁૉࣗମʹର͢ΔϚοϐϯάʯͱ͍͏
ڍಈʹมߋ͞Εͨ
Slide 54
Slide 54 text
Y
type Box = { value: V };
type Boxing= {
[P in keyof T]: Box;
};
type User = {
name: string,
age: number,
};
const boxedUser: Boxing = {
name: { value: "quramy" },
age: { value: 18 },
};
let boxedNumbers: Boxing;
boxedNumbers.concat.value([]); // ???
boxedNumbers.length.value; // ???
Slide 55
Slide 55 text
Y
w LFZPGOVNCFS<>ͷҙຯ͕มΘͬͨΘ͚Ͱͳ͍ʹҙ
type Box = { value: V };
type Boxing= {
[P in keyof T]: Box;
};
const boxedNumbers: Boxing = [
{ value: 1 },
{ value: 100 },
];
Slide 56
Slide 56 text
͍Έͪ
w $POEJUJPOBMUZQF
(FOFSJDSFTUQBSBNFUFST
.BQQFE
UVQMFUZQFͷ߹ΘٕͤͷྫΛհ
w ͓SYKTͷDPNCJOF-BUFTUؔʢ˞1SPNJTFBMMతͳౕʣ
interface Observable {
subscribe(cb: (v: T) => void): void;
}
declare var s1$: Observable;
declare var s2$: Observable;
combineLatest(s1$, s2$).subscribe(([s1, s2]) => {
console.log(s1); // typeof s1 = string
console.log(s2); // typeof s2 = number
});
Slide 57
Slide 57 text
͍Έͪ
interface Observable {
subscribe(cb: (v: T) => void): void;
}
// Inference in conditional type
type StreamType =
T extends Observable ? S : never;
// Mapped tuple type
type Unboxing[]> = {
[P in keyof U]: StreamType;
};
// Generic rest parameters
declare function combineLatest[]>
(...args: U): Observable>;
Slide 58
Slide 58 text
TUSJDU#JOE$BMM"QQMZ
Slide 59
Slide 59 text
TUSJDU#JOE$BMM"QQMZ
w WYͰಋೖ
w GVODUJPOͷCJOEDBMMBQQMZʹର͢ΔνΣοΫ͕ݫີԽ
w WYͷ5VQMFUZQF3FTUQBSBNFUFSTڧԽͷ෭࢈
w TUSJDUΦϓγϣϯϑΝϛϦʔͷͭʢσϑΥϧτͰ0/ʣ
0SHBOJ[F*NQPSU
w WYͰಋೖ
w UTTFSWFS -BOHVBHF4FSWJDF
ʹPSHBOJ[F*NQPSUίϚϯ
υ͕Ճ͞Εͨ
w UTMJOUͷOPVOVTFEWBSJBCMFT JNQPSU
ͷpY૬ͬͯ͘
ΕΔ
Slide 67
Slide 67 text
%FNP
/* before */
import { hoge } from "./lib";
import { foo } from "./lib";
// no used import
import { bar } from "./lib";
hoge();
foo();
/* after */
import { hoge, foo } from "./lib";
hoge();
foo();
Slide 68
Slide 68 text
$PEF'JY4VHHFTUJPO
Slide 69
Slide 69 text
,JOEPG&SSPST
w 5ZQF4DSJQUͷΤϥʔͱͱछྨ
w 4ZOUBY&SSPSͦͦจ๏ͱ͓͔͍ͯ͠͠ͷ
w 4FNBOUJD&SSPSܕෆ߹ͳͲ