Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

About Speaker Ryota Suzuki a.k.a. @uhyo_ › Front-end engineer working on LINE Securities (LINE証券) › TypeScript Lover › Lots of TypeScript articles on Qiita and blog › Several contributions to TypeScript › Also writing a TypeScript book! Twitter: @uhyo_ GitHub: @uhyo Qiita: @uhyo Blog: https://blog.uhy.ooo/

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Development of LINE Securities › TypeScript + React › 150,000+ LoC of TypeScript › 10+ front-end engineers working on the same project

Slide 5

Slide 5 text

Our MUSTs and Type Safety We MUST keep the service up We MUST develop fast We MUST write sustainable code

Slide 6

Slide 6 text

Our MUSTs and Type Safety Types help reduce bugs Types accelerate our development Types contribute to code design

Slide 7

Slide 7 text

Agenda › XLT: Types for i18n Utils › A Custom typescript-eslint Rule › Gradual adoption of noImplicitAny

Slide 8

Slide 8 text

XLT: Types for i18n Utils

Slide 9

Slide 9 text

What is XLT? › In-house i18n system › Admin for text management and API for exporting text › XLT = Cross-Language Translation Tool

Slide 10

Slide 10 text

Our XLT Workflow › 1. Download text data from XLT system › 2. Commit data and use it › (We don’t query data at runtime; it’s not CMS. Rather, it’s for managing text separately from source code)

Slide 11

Slide 11 text

Our Use of XLT › Query text with xlt function › Supports partial application!

Slide 12

Slide 12 text

Type Safety & DX of XLT › Of course, fully type-safe! › Auto completion is there too!

Slide 13

Slide 13 text

Code Generation for XLT › We generate a large type that accepts all possible keys (including partial ones) › Runtime code is fixed TS 4.1’s template literal types might help? !

Slide 14

Slide 14 text

Code Generation is Automated!

Slide 15

Slide 15 text

Bonus: Splitting Runtime Data with Babel

Slide 16

Slide 16 text

A Custom typescript-eslint Rule

Slide 17

Slide 17 text

Background: A Common Pattern with JSX › The {cond && } pattern › Show if cond › Show nothing if not cond (React does not render false) › Simpler than cond ? … : null

Slide 18

Slide 18 text

Actual Code with Bug › noticeTotal is a number | undefined › What if noticeTotal is 0?

Slide 19

Slide 19 text

Actual Code with Bug

Slide 20

Slide 20 text

Actual Code with Bug

Slide 21

Slide 21 text

Summary of the Problem › 0 && … is evaluated to 0 › React renders 0 ! › In general, number && element is very bug-prone › We want to forbid this pattern

Slide 22

Slide 22 text

Our Solution: Custom typescript-eslint Rule @linecorp/jsx-no-number-andand (sorry, not OSS!)

Slide 23

Slide 23 text

Making a typescript-eslint Rule › Get a TypeChecker instance from custom parser › This provides us type information of expressions

Slide 24

Slide 24 text

Making a typescript-eslint Rule › Query && expressions at JSX child positions › Get the type of the left operand › If number is included, emit a lint error

Slide 25

Slide 25 text

Gradual Adoption of noImplicitAny

Slide 26

Slide 26 text

What is noImplicitAny? › Compiler option to forbid parameters without type annotation › Comes with other stricter checks › Without this option, these parameters get the any type! !

Slide 27

Slide 27 text

Let’s Enable noImplicitAny › Advice from me: always enable noImplicitAny when you start a new project › tsc --init already does so!

Slide 28

Slide 28 text

The any Nightmare › The any type propagates ! › Disaster to type safety › The any type disables nearly all compile errors ☠

Slide 29

Slide 29 text

The Problem › We did not have time to solve this all at once › QA would be impratically high-cost › Major part of our codebase did not enable noImplicitAny !

Slide 30

Slide 30 text

Why We didn’t? › Our project used TypeScript from start › But a lot of code was copied from JavaScript project › We didn’t know TypeScript very well, so just chose the easiest way to proceed with it !

Slide 31

Slide 31 text

0 100 200 300 400 500 600 0 20000 40000 60000 80000 100000 120000 140000 160000 2018/07 2018/11 2019/03 2019/07 2019/11 2020/03 2020/07 noImplicitAny errors TypeScript LoC TypeScript LoC Potential noImplicitAny errors The Result

Slide 32

Slide 32 text

0 100 200 300 400 500 600 0 20000 40000 60000 80000 100000 120000 140000 160000 2018/07 2018/11 2019/03 2019/07 2019/11 2020/03 2020/07 noImplicitAny errors TypeScript LoC TypeScript LoC Potential noImplicitAny errors The Result Took one year to solve nearly all errors Without any action, number of potential noImplicitAny errors kept growing

Slide 33

Slide 33 text

0 100 200 300 400 500 600 0 20000 40000 60000 80000 100000 120000 140000 160000 2018/07 2018/11 2019/03 2019/07 2019/11 2020/03 2020/07 noImplicitAny errors TypeScript LoC TypeScript LoC Potential noImplicitAny errors The Result Gradual adoption Short-term attack

Slide 34

Slide 34 text

Our Long-Term Adoption Strategy › No new noImplicitAny errors! › Existing files occasionally get fixed › Disallow noImplicitAny errors in files that have diff (similar to what reviewdog does)

Slide 35

Slide 35 text

Outcome of the New Strategy › Growth of our TypeScript skill (recently CI rarely fails with new noImplicitAny error) › Development schedule is not affected › Of course, safer code (the any type is super unsafe!)

Slide 36

Slide 36 text

Review Carefully › Bad type definitions could fix noImplicitAny errors ! › Review to ensure we have good type definitions

Slide 37

Slide 37 text

The Short-Term Attack › Helps succeeding noImplicitAny fixes › We recommend performing some short-term attack at first

Slide 38

Slide 38 text

How to Do Short-Term Attack › Do the best on type definition quaility › Assign TypeScript master › Fix core modules at first

Slide 39

Slide 39 text

Conclusion Let’s enhance type safety and developer experience by various means!

Slide 40

Slide 40 text

Conclusion › typescript-eslint: Enhance type safety with additional checks! › noImplicitAny: Improve code quality by gradually adopting noImplicitAny! › XLT: Generate code for better type safety & DX!