Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
プロダクト開発とTypeScript
Search
Taketoshi Aono(青野健利 a.k.a brn)
October 02, 2019
Programming
3k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
プロダクト開発とTypeScript
TypeScriptによるプロダクト開発の知見
Taketoshi Aono(青野健利 a.k.a brn)
October 02, 2019
More Decks by Taketoshi Aono(青野健利 a.k.a brn)
See All by Taketoshi Aono(青野健利 a.k.a brn)
document.write再考
brn
6
3.2k
Parsing Javascript
brn
14
9.6k
JSON & Object Tips
brn
1
590
CA 1Day Youth Bootcamp for Frontend LT
brn
0
1.1k
Modern TypeScript
brn
2
890
javascript - behind the scene
brn
3
820
tc39 proposals
brn
0
1k
React-Springでリッチなアニメーション
brn
1
780
javascript internationalization API
brn
0
970
Other Decks in Programming
See All in Programming
メールのエイリアス機能を履き違えない
isshinfunada
0
250
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
140
PostgreSQL 18で考えるUUID主キー
kazuhiro1982
0
500
引き算の組織 ― アウトカムとAIに全振りするために辞めたこと ― / Organization by Subtraction
hirokiyamamoto14
PRO
0
280
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
220
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.1k
バグを直したら useEffect が消えた
colorful12
3
690
React本体のコードリーディング
high_g_engineer
1
150
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
360
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
240
My Marp Sample
sinoue0108
0
110
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.9k
Featured
See All Featured
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.2k
Code Review Best Practice
trishagee
74
20k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
RailsConf 2023
tenderlove
30
1.5k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
We Have a Design System, Now What?
morganepeng
55
8.3k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
180
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
64
56k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
How to Talk to Developers About Accessibility
jct
2
520
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
Side Projects
sachag
455
43k
Transcript
Product development with TypeScript
Name !CSO 5BLFUPTIJ"POP੨݈ར Occupation 'SPOUFOE%FWFMPQFS1SPEVDU0XOFS Company $ZCFSBHFOU"EUFDI4UVEJP"*.FTTFOHFS OSS $POUSJCVUPSPG7
About IUUQJOGPCODI
1SPEVDUEFWFMPQFEFGGFDUJWFMZ 5ZQF4DSJQUಋೖͯ͠ϓϩμΫτ։ൃͷੜ࢈ੑ্͕Γ·͔ͨ͠ʁ ಋೖ͚ͨͩ͠Ͱͳ͔ͳ͔͍͔͠͠Ε·ͤΜɻ ࠓͷτʔΫ͕ ੜ࢈ੑΛͰ͖Δ্͚ͩ͛ΔͨΊͷΨΠυͱͳΔ͜ͱΛئ͍·͢ɻ
*NQPSUBOUUIJOHTBCPVU5ZQF4DSJQU 5ZQF4DSJQUͷॏཁͳͰ͢ KBWBTDSJQUͰͳ͍͕KBWBTDSJQUͰ͋Δ ܕ࣮ߦ࣌ʹফ͑Δ
ػೳ
#FGPSFBMM લఏͱͯ͠UTDPOpHKTPOͰҎԼͷػೳඞͣ0/ʹ͠·͠ΐ͏ OP*NQMJDJU"OZ TUSJDU
*NQPSUBOUUIJOHTBCPVU5ZQF4DSJQU KBWBTDSJQUͰͳ͍͕KBWBTDSJQUͰ͋Δ 5ZQF4DSJQUKBWBTDSJQUͷ4VQFS4FUΛᨳ͍ͬͯ·͢ ͦͷͨΊ༷తʹ+BWBTDSJQUΛ౿ऻ͍ͯ͠·͕͢ ͋͘·Ͱผͷݴޠͱଊ͑ͨ΄͏͕ྑ͍Ͱ͢ ͦͷ্Ͱ͍͔ͭ͘ॏཁͳʹ͍͓ͭͯ͠·͢
FOVN FOVN5ZQF4DSJQUͷಠࣗػೳͰ͢ KBWBTDSJQUʹແ͍ͱ͍͏ҙຯࠓޙಉ ͡ҙຯͰ͍·͢
enum Card { SPADE, HEART, DIAMOND, CLUB } // ࿈൪
assert.equal(Card.SPADE, 0); assert.equal(Card.DIAMOND, 2); // ٯҾ͖ assert.equal(Card[Card.DIAMOND], 'DIAMOND');
enum Event { CLICK = 'CLICK', MOUSEOVER = 'MOUSEOVER'; }
FOVN FOVN͜ͷΑ͏ʹΛ·ͱΊΔͷʹར༻͠·͕͢ FOVN͕ࣗܕΛߏ͠ɺܕνΣοΫʹར༻Ͱ͖·͢ ͨͩ͠ҙ͕͋Γ·͢
enum Card { SPADE, HEART, DIAMOND, CLUB } const fn
= (card: Card) => { return card; } fn(Card.SPADE); // OK fn(0); // OK fn(10); // OK
FOVN FOVNΛͦͷ··ར༻͢Δͱɺ୯७ͳOVNCFSܕͱͳΓͷൣғΛνΣο Ϋͯ͘͠Ε·ͤΜ ͦͷͨΊෆਖ਼ͳΛ͢͜ͱՄೳʹͳΓ·͢
enum EventType { CLICK = 'CLICK', MOUSEOVER = 'MOUSEOVER'; }
const fn2 = (event: EventType) => {return event;} fn2(EventType.CLICK); fn2(EventType.MOUSEOVER); fn2("MOUSEDOWN"); // NG
FOVN จࣈྻΛͬͨ߹ʹਖ਼͘͠FOVNʹఆٛ͞Ε͍ͯΔͷνΣοΫΛߦ ͍·͢ ·ͨΛܕͱͯ͠͏͜ͱͰ5BHHFE6OJPOͱͯ͠͏͜ͱ͕Ͱ͖·͢
enum EventType { CLICK = 'CLICK', MOUSEOVER = 'MOUSEOVER'; }
interface ClickEvent { type: EventType.CLICK; } interface MouseDownEvent { type: EventType.MOUSEOVER; } declare const clickEvent: ClickEvent; declare const mouseDownEvent: MouseDownEvent; const fn3 = (event: ClickEvent) => { return event; } fn3(clickEvent); // OK fn3(mouseDownEvent); // NG
FOVN FOVNศརͰ͕͢ɺͷ߹ܕ͚ͩͰ੍ޚͰ͖ͳ͍ͷͰɺ ͱͯ͠ར༻͢Δ߹ݺͼग़͞ΕΔଆͰൣғͷνΣοΫΛ͠·͠ΐ͏ɻ
/BNFTQBDF OBNFTQBDF5ZQF4DSJQUಠࣗػೳͰ͕͢ &4.PEVMFTͷ͓͔͛Ͱ༨Γ͏ҙຯͳ͘ͳΓ·ͨ͠ ͜ͷػೳએݴϑΝΠϧҎ֎Ͱ͏ͷࠞཚͷݩͳͷͰ͏ඞཁͳ͍Ͱ ͠ΐ͏
/VMMPSVOEFpOFE KBWBTDSJQUʹͭͷແޮͳ͕͋Γ·͢ OVMMͱVOEFpOFEͰ͢ VOEFpOFE͕ະఆٛͷ߹ʹར༻͞ΕɺOVMM݁Ռ͕ଘࡏ͠ͳ͍࣌ʹ ΘΕ·͢ ͕ͦͷ͍͚ʹରͨ͠ҙຯ͋Γ·ͤΜ ࠞཚ͢Δ͚ͩͰ͢
*O5ZQF4DSJQU OVMMVOEFpOFE5ZQF4DSJQU্Ͱ໘Ͱ͢ TUJSDU/VMM$IFDLT0/ʹ͖͢Ͱ͕͢ɺVOEFpOFEͷνΣοΫ͞Ε·ͤΜ
.BZCFPS0QUJPOBM OVMMɺVOEFpOFEXSBQͯ͠͠·͍·͠ΐ͏ɹ
type Optional<T> = T | undefined | null;
0QUJPOBM ຊདྷ0QUJPOBMΫϥεʹͯ͠͠·͍͍ͨͱ͜ΖͰ͕͢ 5ZQF4DSJQUͰ0QUJPOBM$IBJOJOH͕ೖΔͷͰ ΑΓ5ZQF4DSJQUωΠςΟϒͰऔΓѻ͑Δϑϥοτͳܕͷ΄͏͕ྑ͍Ͱ͠ΐ͏
type Optional<T> = T | undefined | null; declare const
obj: Optional<{value?: string}>; // ·ͩಈ͖·ͤΜ // or obj?.value || ‘’ // force obj!.value!
࣮
%FWFMPQXJUI5ZQF4DSJQU 5ZQF4DSJQUΛͬͯ։ൃ͢Δ߹ͷ࣮खॱKBWBTDSJQUͱେ͖͘ม͑· ͠ΐ͏
*OUFSGBDF'JSTU ࠷େࣄͳ͜ͱநతͳ࣮Λ࠷ॳʹߦ͏͜ͱͰ͢ ͦΕͭ·Γ۩ମతͳϩδοΫ͔ΒΕΔ͜ͱͰ͢ 5ZQF4DSJQUJOUFSGBDFͱUZQFʹΑͬͯͦΕΛՄೳʹ͍ͯ͠·͢ ِ3FEVYΈ͍ͨͳྫΛհ͠·͢
interface Todo { id: string; date: Date; title: string; done:
boolean; } type Todos = Todo[]; interface State { todos: Todos; } type Payload = { type: "ADD", } | { type: "DELETE" payload: {id: string}; } const reducer = (payload: Payload, state: State): State => { return state; }
-PHJDJTMBUFS SFEVDFSͷ࣮Ҏ֎શͯܕͷΈͰ࣮͞Ε͍ͯ·͢ SFEVDFSதۭͰΛฦ͚ͩ͢Ͱ͢ ͔͜͠͠ΕͰϓϩάϥϜͷࠎͰ͖͍ͯ·͢ ͋ͱSFEVDFSͷ࣮ʹूத͢Δ͚ͩͰ͢
-PHJDJTMBUFS ۃͳ۩ମతͳΞϧΰϦζϜ͋·ΓॏཁͰ͋Γ·ͤΜ σʔλߏɾܕ͕ͬͱॏཁͰ͢ ͕ܾ͜͜·Εେ֓ΞϧΰϦζϜࣗવͱಋ͔Ε·͢
ڥք
7JSUVBMBOE3FBM ࠷ॳʹड़ͨΑ͏ʹ5ZQF4DSJQU͋͘·ͰԾͷܕΛ࣋ͭݴޠͰ͢ ͦͷͨΊɺ࣮ࡍʹ࣮ߦ͞ΕΔ߹ʹͱܕͷဃ͕ى͖ΔՄೳੑ͕͋Γ· ͢
4FQBSBUFE8PSME ಛʹဃ͕ى͖͍͢ͷ͕ɺ֎෦ͱͷڥքͱͳΔ෦Ͱ͢ "1*αʔόͱͷڥք ϒϥβετϨʔδͱͷڥք
"EBQUFS ͨͩ͠ɺٯʹݴ͑͜ΕΒͷڥք͑͑ͯ͞ɺઌఔͷJOUFSGBDFઌߦͷ࣮ Λߦ͑ဃΛΒ͢͜ͱ͕Ͱ͖ΔͷͰͳ͍Ͱ͠ΐ͏͔ʁ ·ͨ1SPUP#VGͷΑ͏ͳ54ࣗಈੜܥΛ͏ͷखͰ͢
1SPHSBN 1SPHSBN 1SPHSBN "EBQUFS &YUFSOBM*OUFSGBDF
$MFBO"SDIJUFDUVSF ·ΔͰ$MFBO"SDIJUFDUVSFͷϨΠϠʔਤͷΑ͏ʹͳΓ·ͨ͠ ͔͠͠ɺผʹ$MFBO"SDIJUFDUVSFΛར༻͠Ζͱݴ͍ͬͯΔΘ͚Ͱͳ͘ 5ZQF4DSJQUͷԾܕͱ͍͏Έʹͱͬͯ"EBQUFSඇৗʹॏཁͳҙຯΛ ࣋ͪ·͢ ͲΜͳΞʔΩςΫνϟΛ࠾༻͍ͯͯ͠֎෦γεςϜڥքΛਖ਼͑͘͠Δ͜ ͱͰɺ5ZQF4DSJQUͷܕΑΓҰཱͭͰ͠ΐ͏
5P5ZQFE ࠓ·Ͱͷ࠷ॳ͔Β5ZQF4DSJQUͰ։ൃ͍ͯ͠ΔέʔεΛલఏͱ͍ͯ͠·͢ ͕ ͠طଘͷKBWBTDSJQU͔ΒҠߦ͢Δ߹֎෦ڥք͔ΒܕΛ͚͍ͯ͘ͱΑ ͍Ͱ͠ΐ͏ ·ͨɺਖ਼͍͔ͨ͠ͱਖ਼͘͠ͳ͍ܕΛڥքΛه͓ͯ͘͜͠ͱ͕େࣄͰ͢
"OZBEBQUFS ܕ͚͞Ε͍ͯͳ͍ةݥͳྖҬશͯɺਖ਼͍͠ܕ͔Βมͨ͠ͱ͍͏ҹΛ ͚͓ͭͯ͘ͱϦϑΝΫλϦϯά͕͍͢͠Ͱ͢
type UncheckedFixme<T> = any; interface Model {} const unTypedFn =
(a: UncheckedFixme<Model>) { }
"OZBEBQUFS 6ODIFDLFE'JYNF5͕ͲΜͲΜίʔυͷίΞྖҬʹԡ͠ࠐ·ΕΔ·ͰϦ ϑΝΫλϦϯά͚ͭͮ͠·͠ΐ͏ ͦͯ͠࠷ޙʹίʔυத͔Βফͯ͠͠·͍·͠ΐ͏ ͜ͷΑ͏ͳ#PUUPN6Qతͳܕͷ͚ํΛ͢Δͱɺ֎෦ͷةݥͳྖҬ͔Β҆શ ͳ෦ഭ͍ͬͯ͘ͷͰܕͷϛε͕ى͖ͮΒ͍Ͱ͢ ͪͳΈʹ6ODIFDLFE'JYNF5-JOUΤϥʔग़ΔՄೳੑ͕͋ΔͷͰ௵͓ͯ͠ ͍͍ͯͩ͘͞
ίʔσΟϯά
5ZQFJTCPUIFS ܕ͚݁ߏ໘Ͱ͢ ࠷ॳʹJOUFSGBDFͰܕఆٛΛͪΌΜͱ͓ͯ͘͠ͱزจ͔ղফ͞Ε·͕͢ ຊ࣭తʹՃతͳ࡞ۀͳͷͰαϘΓ͕ͪͰ͢
.BZCFXSPOH ͨͩɺܕ͚ͷ໘͘͞͞ίʔυͷ·͔ͣ͞͠Ε·ͤΜ
class Test { private value: {[key: string]: string} | null;
constructor() {} public setValue(value: {[key: string]: string}) { this.value = value; } public doSomething() { return this.value!['key'] // you need to through type check. } }
*OJUJBMJ[FMBUFS ͜ͷΑ͏ͳޙʹॳظԽ͞ΕΔϝϯόมܕͰදݱ͢Δͷ͕ࠔͰ͢ ͞Βʹ/VMMBCMF͔VOEFpOFEΛڐ༰͢Δܕʹͨ͠߹ʹ͍͍ͪͪ Λॻ͘ͷةݥ͔ͭ໘Ͱ͢ ͜ͷΑ͏ͳɺͦͦܕͰදݱ͢Δͷ͕͍͠ίʔυΛආ͚ΔΑ͏ʹ͢Δͷ ͕ྑ͍Ͱ͢ ࠓճͷέʔεͰݴ͑શͯDPOTUSVDUPSͰॳظԽ͖͢Ͱ͢
function getValue() { let value: {[key: string]: number} | null
= null; if (x) { value = {key: 1}; } else { value = {value: 1}; } return value; }
*OJUJBMJ[FMBUFS JGจͷதͰมΛॳظԽ͢ΔͷΛ͚ͯ͞ɺJGจΛؔԽͯ͠͠·͍·͠ΐ͏
.PSFUZQBCMFDPEF ΑΓγϯϓϧʹܕ͚Ͱ͖Δίʔυ ਓؒʹಡΈ͘͢ཧղ͍͢͠ίʔυͱͳΓ·͢ ͪΖΜ͖Ε͍ʹॻ͍ͯෳࡶͳܕΛ࣋ͭέʔε͋Γ·͢͠ɺશ͕ͯͦͷ ͱ͓ΓͰ͋Γ·ͤΜ͕ ෳࡶͳܕػೳΛ͏લʹίʔυͷߏ͕ਖ਼͍͔֬͠ೝͯ͠Έ·͠ΐ͏
·ͱΊ 5ZQF4DSJQUͰͷ։ൃʹ͍ͭͯͷτʔΫͰͨ͠ ͜ΕΒͷ5JQT͕͋ͳͨͷ։ൃͷखॿ͚ʹͳΔͱ͍Ͱ͢ ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠