# React + Typescript - React compelte guide
###### tags: `Javascript, React, Typescript`
# Module Intro
> Typescript is a "superset" to Javascript
> 指的是 typescript 是 Javascript 的語法延伸
簡單舉個例子可以使用 Typscript
```javascript=
function add(a,b){
return a+b;
}
const result = add(2,5);
console.log(result);
```
這邊是個簡單的 JS function ,並且會在瀏覽器的 console 內顯示 7,這邊沒有問題
但是如果我們在 add 內部放入 `add('2','5')`,顯示的結果會是 25 ,因為JS是動態型別的語言,問題來了如果在大型專案底下,共同協作的人不知道這邊的 add function 應該填入的其實是數字型別的話就會出大錯而找不到問題了,Typescript 這時候就可以進場了!

可以從上圖中看出,給於參數設定好型別,下方帶入參數如果沒有對應好則會直接 IDE 告訴你出錯了,非常方便
# Installing & Using Typescript
`npm install typescript`
需要注意的地方是 Typescript 的扣不會跑在瀏覽器裡面,因此我們必須 compile Typescript to Javascript ,因此需要使用 compiler
`npx tsc 後方填入 typescript設定檔檔名`

輸入之後會產生一個新的 JS 檔案幾乎跟 TP 的內容一樣,這時候這個 JS 檔就可以引入 index.html 瀏覽器就可以使用它摟 !
# Exploring the Base Types
## Primitives: numbers, strings, boolean, symbols, null, undefined
這邊的型別要注意的是大小寫
**如果 number 寫成 Number 會變 Number 物件在 JS 中**
```typescript=
let age:number = 8;
let userName:string = 'Mark';
let isInstructor:boolean = true;
```
當然 null, undefined 也可以這樣處理,只是一般不會這樣使用,會在下面的章節繼續介紹
## More complex types: arrays, objects
這邊可以針對 array 的內容做型別設定
```typescript=
let hobbies: string[] = ['Sports','Cooking']; // 只能放入字串進這個 array
```
這邊針對物件做設定,首先我們不做任何設定卻沒有得到錯誤是因為
當不設定 let person 時其實它預設的型別就是 any ,也可以寫進去設定 any 不過一般不會這樣使用因為這樣就是一般的 JS 了
```typescript=
let person;
person = {
name:'Max',
age:32
}
```
因此一般物件的寫法可以這樣寫,來設定好物件內部 value 的型別,然而只要 key, value 任一個值不符合規定就會顯示錯誤訊息
```typescript=
let person:{
name:string;
age:number;
}
```
這邊的這個物件就會顯示錯誤訊息,因為 key, value 的部分都不符合設定
```typescript=
person = {
isEmployee:true
}
```
### 結合 array, object
可以這樣設定就會呈現出一個都是 people 物件的 array 搂 !
```typescript=
let people:{
name:string;
age:number;
}[];
```
# Type inference
> Typescript 有個很強大的功能就是會自動推測你的變數的型別
以下圖為例,明明還沒有定義型別給它,它卻已經自動報錯了

這個特色可以讓使用 Typescript 減少很多打字的時間,因為 Type inference 這個特性
# Using Union Types
> Union Types 代表可以允許不只一種 types 存在
讓下方的程式碼不報錯
```typescript=
let course: string | number = 'React';
course = 12341;
```
# Understanding Type Aliases(別名)
> 就像是把常用的 type 建立一個模型,用來套入其他的變數當中使用被稱為 Type alias ,可以避免重複撰寫型別設定
以下方程式碼為例,使用 type 關鍵字寫型別設定後使用在 let person 中,這樣一來之後要使用到 Person 這個設定的話只要帶入 Person 即可不用再重複設定型別
```typescript=
type Person = {
name:string;
age:number;
};
let person:Person = {
name:'Max',
age:32
};
```
當然也可以針對設立好的 type 的關鍵字做操作
```typescript=
let people:{
name:string;
age:number;
}[];
```
就會轉變成
```typescript=
let people:Person[];
```
# Function & Function Types
> 參數有型別,funciton 本身也有
這裡可以看到 Types inference 的痕跡,明明我們沒有定義 function 的型別,這邊卻自動加上了

當然我們也可以這樣寫,不過通常前面參數定義好之後後面的 function 可以就讓它推測就好,這邊要強調的是不只是**參數有型別,funciton 本身也有**
```typescript=
function add(a:number, b:number):number{ // 也可以使用 Union Type
return a + b;
}
```
### function with no return value
>
> 這樣沒有返回值的函式會被定義為 void,基本上跟 null, undefined 差不多但是只會用在 functions 連接上,代表這個 function 沒有 return
```typescript=
function printOutput(value:any) {
console.log(value);
}
```

# Diving into Generics
這邊先來解釋什麼情境下要使用 Generics
下方的程式碼因為要在陣列前面加入新的 value ,型別定義上面使用了 any ,畢竟你不確定會加入的是什麼樣的型別的 value ,但是問題來了因為參數型別上面設定了 any,導致 updateArray 在使用 insertAtBeginning 函式時就算使用了 .split 這個使用在字串型別的方法,Typescript 依舊不會報錯,因為目前的型別就是 any 等於關閉了 Typescript 功能,這時候就可以用 Generics 搂 !
```typescript=
function insertAtBeginning(array:any[],value:any){
const newArrray = [value, ...array];
return newArray;
}
const demoArray = [1,2,3];
const updateArray = insertAtBeginning(demoArray, -1); // [-1,1,2,3]
updateArray[0].split('');// 只有引擎會報錯,Typescript 不會有反應
```
## Generics
> Generics 就像是讓 functions 可以根據參數推測返回值型別的方法,幫助我們撰寫 function 可以 type safe yet flexible
在 function 名稱後面加入一個 `<T>` 並且套用在後面參數使用上面,這麼一來 Typescript 就會明白 demoArray 是 number 型別,而後面的 -1 也是 number 型別,所以 return 的函式一樣也是 number 型別,於是下方的 split 方法就出錯了顯示在 IDE 上!(因為它只接受字串)

```typescript=
function insertAtBeginning<T>(array:T[],value:T){
const newArrray = [value, ...array];
return newArray;
}
```

## Generics 可以推測函式的型別但只限一次一種
從下圖可以看出,這邊另一個 stringArray 放入的都是 string ,因此這個函式的型別就會返回 string 的值

而一次一種的意思代表,參數的值必須是統一的
比方說 : 都是 number 型別會產出 的 function 返回值一定也是 number 型別,以此類推
## A Closer Look At Generics
這邊要告訴我們的是 Array 其實也是使用 Generics ,例如下面兩個範例其實是一樣的
```typescript=
let numbers: number[] = [1, 2, 3];
```
```typescript=
let numbers: Array<number> = [1, 2, 3];
```
針對課堂上面的範例也可以這樣去寫就可以針對 function 定義型別,但我覺得用關鍵字 T 去寫會有更高的彈性,不過當 Typescript 沒有辦法正確的推測型別時,直接幫它加上 Generics 型別也是一個方法
```typescript=
const stringArray = insertAtBeginning<string>(['a', 'b', 'c'], 'd');
```
# Creating a React + Typescript Project
基本上就可以直接使用[官網](https://create-react-app.dev/docs/adding-typescript/)的操作下載一個 React app + Typescript
```npm=
npx create-react-app my-app --template typescript
# or
yarn create react-app my-app --template typescript
```
我們從 source folder 可以觀察出
部分檔案他是以 tsx 結尾,如果檔案中同時使用了 typescript 以及 JSX 就必須這樣寫

接下來可以看看 package.json 內的插件
* 上面四個 types 主要擔任 JS 以及 TS 之間的橋梁
* 下方的紅框就是 TS 以及 compiler 本身

# Work with Array & Object Types
這邊會簡單設置一個 Todo.tsx component 並且放置進去 App.tsx 做使用
## Todos.tsx
目前因為還沒有添加 Typescript 進去所以跟一般的 react component 是一模一樣的
```jsx=
function Todos() {
return <ul>
<li>Learn React</li>
<li>Learn Typescript</li>
</ul>
}
export default Todos;
```
## App.tsx
既然目前版本的 root component 都不用引入 react 了那麼 TS 版本自然也不需要做這件事情
```jsx=
import Todos from './components/Todos';
import './App.css';
function App() {
return (
<div>
<Todos/>
</div>
);
}
export default App;
```
# Working with Props & Typescript
首先我們要把 ul 內我們寫死的內容拔掉來透過 props 傳入,從下圖可以看出,由於 props 尚未設定好所以 IDE 已經告訴我們了,這邊是從衍伸 TS 的功能(提示錯誤功能)
並且這個 props 目前的 type 是 any ,針對這個 props 由於我們還沒有定義其型別,所以盡量還是要使用 props:any 來避免這個錯誤發生(但這樣做 TS 就沒有效果所以比較好的寫法在下方),不過這個部分如果覺得太嚴格可以到 tsconfig.json 中做調整

首先我們設定 props 的型別為物件並且包含了字串型別的陣列,這邊很正常沒問題
```jsx=
import React from 'react';
function Todos( props: { items:string[], children }) {
return (
<ul>
{ }
</ul>
)
}
export default Todos;
```
但是不要忘了還有一個特殊的 prop : children 它的型別尚未定義,當然我們可以依樣畫葫蘆直接給 children 設定型別給它,但是每個我們要使用的 component 都要這樣設定非常麻煩
因為每一 component 其實都有 children prop 因此這邊 TS, React 給它個特殊的寫法做簡化,使用 Generic type 來操作避免重複撰寫一樣的程式碼
**實際的作法是把外面的 Todos functional component 直接轉換為 generic function**
1. 首先把函式本身改為箭頭函式
2. 針對 Todos 函式本身設定 React.FC 也就是 Function component(可以看到其位置於 node_modules/@type/react/index.d.ts 可以找到)
```javascript=
type FC<P = {}> = FunctionComponent<P>;
```
3. 這個時候 children 就變成了 props 的屬性可以來操作

```jsx=
import React from 'react';
function Todos: React.FC = (props) => {
return (
<ul>
{props. }
</ul>
)
}
export default Todos;
```
4. 下一步即可把 item 的型別設定混和進去使用即可選用 items/children 搂

```jsx=
import React from 'react';
function Todos: React.FC<{ item:string[] }> = (props) => {
return (
<ul>
{props. }
</ul>
)
}
export default Todos;
```
但是要特別注意跟之前使用過的 T type 不一樣,那邊是我用 T type 來定義之後的型別都會一致,比方說都會是 string, number 等等(**這邊是我們自行定義的 Generics type**)
```jsx=
function insertAtBeginning<T>(array:T[],value:T){
const newArrray = [value, ...array];
return newArray;
}
```
**然而 React.FC 原本就是 generics type**
5. 接下來就可以操作 map 印出 props 資料瞜
App.tsx 部分要先寫上要 demo 的字串
```jsx=
function App() {
return (
<div>
<Todos items ={['123','456']}/>
</div>
);
}
```
Todos.tsx 部分就可以 map 出內容瞜 !
```jsx=
import React from 'react';
const Todos: React.FC<{items:string[]}> = (props) => {
return (
<ul>
{props.items.map(item => <li key={item}>{item}</li>)}
</ul>
)
}
export default Todos;
```
印出結果:

# Adding a Data Model
因為 todo 不可能只有 items 內容而已,而是會有很多資料在其中,比方說建立時間、作者等等,因此這邊我們建立一個 todo.ts 檔案來定義 todos
寫法跟建立物件實體很像
### todo.ts 用來定義 todo 的 type
```typescript=
class Todo {
id: string,
text: string
}
export default Todo;
```
但是卻報錯了,內容是關於這邊建立的 class 的 key 放入 value 只有放入型別,以及沒有使用 `constructor()` 來讓其實體化

```typescript=
class Todo {
id: string;
text:string; //純 JS 不需要使用到型別定義
constructor (todoText: string) {
this.text = todoText;
this.id = new Date().toISOString();
}
}
export default Todo;
```
在純 JS 定義 class 中不會使用上方的型別定義
## 操作剛剛定義好的型別 Todo 在 App.js 中
操作也跟普通 JS 很像 new 下關鍵字並且帶入參數使用
```typescript=
function App() {
const todos =[
new Todo('tttest'),
new Todo('test')
];
return (
<div>
<Todos items={todos} />
</div>
);
}
```
### Todo.tsx 中 map 出來 items 內容
這邊引入我們製作好的 todo 型別放到我們設定的 generics type 中
```typescript=
import React from 'react';
import Todo from '../models/todo'
const Todos: React.FC<{ items: Todo[] }> = (props) => {
return (
<ul>
{props.items.map( item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
)
}
```
呈現的內容跟剛剛一模一樣,不過型別更嚴謹摟!
# Time to practice: Exercise Time!
> 練習的內容在於把 li 這個元件拉出來去做一個 todoItem
因為其需要的 props 就是單純的 text 就好所以不用拉整個 todo.ts 來使用
## todoItem.tsx
```typescript=
import React from 'react';
const TodoItem: React.FC<{ text:string }> = (props) => {
return (
<>
<li>{props.text}</li>
</>
)
}
export default TodoItem;
```
## Todos.tsx
這邊引入剛剛製作的 component TodoItem ,**這邊需要留意的是除了 text 是 TodoItem 本來就需要的 props 之外,因為我們給 Todos.tsx 設定為 React.FC 這個 type 了,因此其 ul 底下的 li 自動就可以使用 key 這個屬性**
```typescript=
import React from 'react';
import Todo from '../models/todo'
import TodoItem from '../components/TodoItem'
const Todos: React.FC<{ items: Todo[] }> = (props) => {
return (
<ul>
{props.items.map( item => (
<TodoItem key={item.id} text={item.text}></TodoItem>
))}
</ul>
)
}
export default Todos;
```
# Form Submissions In TypeScript Projects
> 這邊的練習就是製作新的 component NewTodo.tsx ,以及認識 form 常用到的 FormEvent type
## NewTodo.tsx
* 首先把整個 jsx 寫好
* 接下來會注意到 submitHandler 處的參數 event 必須要加上 type FormEvent ,並且從 react 引入使用
* 接下來把函式連接到 onSubmit 上面,這邊如果輸入不是 FromEvent 也會報錯(因為 submit 事件一般使用都是搭配 FormEvent )
```typescript=
import { React,FormEvent } from "react";
const NewTodo = () => {
const submitHandler = (event: FormEvent) => {
event.preventDefault();
};
return (
<form onSubmit={submitHandler}>
<label htmlFor='text'>Todo Text</label>
<input type="text" id="text" />
<button>Add Todo</button>
</form>
)
};
export default NewTodo;
```
# Working with refs & useRef
> 操作取得 form input 的值有幾種方式,如 useState 或是 useRef 這邊操作後者
```typescript=
import { FormEvent, useRef } from "react";
const NewTodo = () => {
const todoInputRef = useRef();
const submitHandler = (event: FormEvent) => {
event.preventDefault();
};
return (
<form onSubmit={submitHandler}>
<label htmlFor='text'>Todo Text</label>
<input type="text" id="text" ref={todoInputRef}/> // 這邊會出現問題,因為不確定上面的 useRef 會應對哪一種 type
<button>Add Todo</button>
</form>
)
};
export default NewTodo;
```
從下圖中可以看到,當輸入 type 給 useRef 後可以看到各種 HTML 對應的事件的 type 可以從 MDN 去查詢

隨後給予 useRef 預設值填入 null 後錯誤就解除了!
所以當我們在 typescirpt 中使用到 useRef 要特別注意到幾件事情:
1. useRef 要根據對應到的 html 設定它的型別
2. 記得填入預設值,不然會報錯
3. 這種類似的 HTML 系列的 type 可以去 MDN 查找,不過通常是 HTMLInput...\HTMLButton...
接下來需要取用到 useRef 的值,可以發現除了 auto complete 的選項幫你含進去了 input 的一些 properties 很方便之外,當 value 使用 auto complete 時卻出現了一個問號,不加還會報錯(如下圖

* 他代表 typescript 不確定 useRef 是否有連接到任何 html tag 或是他的值會不會是 undefined 因此使用問號
* 如果想要明確的表現 useRef 保證可以正確連接到 html tag 則可以使用驚嘆號

最後一個步驟加上一個簡單的驗證給 input
如果修剪到 enteredText 的空白處使用 `trim()` 其長度還是為 0 則直接結束函式
```typescript=
if (enteredText.trim().length === 0) {
return;
}
```
下一個步驟要把這邊 input 輸入的內容回傳到 App.tsx
# Working with "Function Props"
> 如果要在 NewTodo 把 input 內容回傳回去 App 的話,就必須傳遞函式作為 props ,也就是這個章節要介紹如何使用 function type 在 typescript 中
## NewTodo.tsx
從扣中可以看到,當設定好 NewTodo FC 後 onAddTodo 是我們從 App 傳下來的 props ,他的形式
`() => `
* 左邊的括號中間要定義的是參數的 type
* 右邊的箭頭過去則是指返回值 return 的 type
這邊 retun 因為沒有發生所以使用 void
```typescript=
const NewTodo: React.FC<{ onAddTodo: ( text:string ) => void}> = (props) => {
//...省略
props.onAddTodo(enteredText);
};
```
## App.tsx
從這邊可以看到引入 NewTodo 之後來把 onAddTodo 寫上 attr 並且把函式傳下去,記得函式的參數要定義為 string
```typescript=
function App() {
const addTodoHandler = (todoText:string) => {
// 沒有 return 值
};
// 省略
return (
<div>
<NewTodo onAddTodo={addTodoHandler} />
<Todos items={todos} />
</div>
);
}
```
# Managing State & TypeScript
> 這邊我們要操作 useState 來更新畫面,但記得使用 typescript 會有些不一樣的地方!
## App.tsx
這邊我們會按照一般的方式做,解構出 state 跟 setState 最後放入預設值
```typescript=
function App() {
const [todos, setTodos] = useState([]);
const addTodoHandler = (todoText:string) => {
};
return (
<div>
<NewTodo onAddTodo={addTodoHandler} />
<Todos items={todos} />
</div>
);
}
```
然而,最後放入預設值空的陣列時, todos state 卻變成 `never []` 這個 type ,代表它永遠都是空陣列,並且不會被修改,這絕對不是我們想要的狀況

這邊的解法也很容易,針對 useState 的內容用 type 做定義,既然裡面的 state 就是 todo 所以就用我們設定好的存在 module 內 Todo type 來設定即可

下一步要做的事情是把 NewTodo.tsx 傳上來的 todoText 做實體化 new 它,並且命名為 newTodo 最後操作進去 setTodos 並且 concat 進去 prevTodo 產生新的 Todo 物件來更新 state
```typescript=
function App() {
const [todos, setTodos] = useState<Todo[]>([]);
const addTodoHandler = (todoText:string) => {
const newTodo = new Todo(todoText);
setTodos( (prevTodo) =>{
return prevTodo.concat(newTodo);
});
};
return (
<div>
<NewTodo onAddTodo={addTodoHandler} />
<Todos items={todos} />
</div>
);
}
```
哇啦!成功啦~

# Adding Styling
> 這邊的 styling 跟之前課程一樣使用 module 來修飾 todoList 操作過程也一樣
這邊以 TodoItem.tsx 為例子
* 引入 TodoItem.module.css
* 在要修飾的 html 使用 className 並帶入使用
```typescript=
import React from 'react';
import classes from './TodoItem.module.css'
const TodoItem: React.FC<{ text:string }> = (props) => {
return (
<>
<li className={classes.item}>{props.text}</li>
</>
)
}
export default TodoItem;
```
# Time to Practice: Removing a Todo
> 移除 todo 是這邊的練習
## TodoItem.tsx
* 首先做出 X 按鈕
* 綁定 onClick 事件,因為要把 state 往上傳遞所以使用函式帶入參數的方式
* TodoItem 必須新增函式 type ,這邊因為帶入的參數因為要操作到的參數不在這一層所以不填
```typescript=
const TodoItem: React.FC<{ text:string; onDeleteTodo: () => void }> = (props) => {
return (
<>
<li className={classes.item}>
{props.text} <button onClick={props.onDeleteTodo}>X</button>
</li>
</>
)
}
```
## Todo.tsx
> 這一層會重點操作放入 onDeleteTodo 的參數
因為資料主要在這個 component 中 map 進去 TodoItem 內,所以也在這邊處理 onDeleteTodo 的參數
因為要繼續把 onDeleteTodo 往上傳回去 App.js 修改 state:
1. 使用 onDeleteTodo attr 並且放入指向的函式並且使用 `.bind()` 來放入 item.id
2. 因為確定了放入的參數,因此在這一層開始的函式 type 都必須加上 id 的 type string
3. 因為函式 type 的 return 不操作所以一樣使用 void
```typescript=
const Todos: React.FC<{ items: Todo[]; onDeleteTodo: (id: string) => void }> = (props) => {
return (
<ul className={classes.todos}>
{props.items.map( item => (
<TodoItem key={item.id} text={item.text} onDeleteTodo={props.onDeleteTodo.bind(null, item.id)}/>
))}
</ul>
)
}
```
## App.js
> 因為更新 todos 的 state 在這一層,因此 deleteHandler 只能操作在這邊
1. 使用 onDeleteTodo attr 並且指向 deleteHandler
2. deleteHandler 函式參數使用 type id: string ,並且使用 setTodos 更新 state
3. setTodos 內操作好 filter 篩選出不是參數 id 的其他 todo 物件並且更新 state
```typescript=
function App() {
const [todos, setTodos] = useState<Todo[]>([]);
const addTodoHandler = (todoText:string) => {
const newTodo = new Todo(todoText);
setTodos( (prevTodo) =>{
return prevTodo.concat(newTodo);
});
};
const deleteHandler = (id: string) => {
setTodos( (preTodo) => {
return preTodo.filter( todo => todo.id !== id)
});
};
return (
<div>
<NewTodo onAddTodo={addTodoHandler} />
<Todos items={todos} onDeleteTodo={deleteHandler}/>
</div>
);
}
```
刪除功能就完成摟!

# The Context API & TypeScript
> 因為 prop 傳上傳下很麻煩嗎?這邊來示範操作 useContext 使用在 Typescript 中
* 首先要先建立 todo-context.tsx 檔案,並且把所有的 state 以及傳輸的函式全部撈進來
* 處理 TodoContexgObj 避免一直重複撰寫 TodoContex 的 type 使用 type alias
* 要操作 useContext 就必須藉由 createContext 這個 React 的函式來操作並且帶入參數也就是 TodoContext
* 創造 TodoContextProvider 來包裹著全部需要使用到 props 的內容
* 接著把 state 以及相關的函式都丟進去
* 最後使用 FC 的特性操作 children 接收所有的 value 也就是 contextValue
* 下一步就是把其他 component 中的 props 全部刪掉換成這邊輸出的 value 摟!
```typescript=
import React, {useState} from 'react';
import Todo from '../models/todo'
type TodoContextObj = {
item:Todo[];
addTodo: (text:string) => void;
removeTodo: (id:string) => void;
};
export const TodoContext = React.createContext<TodoContextObj>({
item: [],
addTodo: () => {},
removeTodo: () =>{}
}
);
const TodoContentProvider: React.FC = (props) => {
const [todos, setTodos] = useState<Todo[]>([]);
const addTodoHandler = (todoText:string) => {
const newTodo = new Todo(todoText);
setTodos( (prevTodo) =>{
return prevTodo.concat(newTodo);
});
};
const deleteHandler = (id: string) => {
setTodos( (preTodo) => {
return preTodo.filter( todo => todo.id !== id)
});
};
const contextValue: TodoContextObj = {
item: todos,
addTodo: addTodoHandler,
removeTodo: deleteHandler
};
return (
<TodoContext.Provider value={contextValue}>
{props.children}
</TodoContext.Provider>
)
}
export default TodoContentProvider;
```
## App.tsx
可以看到 App 變得非常精簡,因為所有的函式以及 state 都被移動到 context 中摟!需要注意的地方是,這邊需要包裹著整個 App 所以要引入 TodoContentProvider
```typescript=
function App() {
return (
<TodoContentProvider>
<NewTodo/>
<Todos/>
</TodoContentProvider>
);
}
```
## Todo.tsx
這邊示範操作 Todo.tsx
使用 useContext 的方式很簡單,指派給變數之後帶入 TodoContext 這邊記得也要引入
下一步刪掉 props 替換成指派的變數 todoCtx 就大功告成啦
要特別注意的地方,因為原本的 props 被 useContext 的內容取代了,所以 FC 關於 props 的 type 要記得刪掉摟!
```typescript=
const Todos: React.FC = () => {
const todoCtx = useContext(TodoContext);
return (
<ul className={classes.todos}>
{todoCtx.item.map( item => (
<TodoItem key={item.id} text={item.text} onDeleteTodo={todoCtx.removeTodo.bind(null, item.id)}/>
))}
</ul>
)
}
```
# Bonus: Exploring tsconfig.json
這邊簡單介紹幾個設定檔內功能
```typescript=
{
"compilerOptions": {
"target": "es5", // 這邊代表會把 typescript 編譯為 es5 讓更多瀏覽器使用
"lib": [// 使用的函式庫,第一個 dom 舉例 HTMLInputElement 就是其中的內建 type
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,// 這邊可以讓純 js 跟 typescript 檔案可以並存
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true, // 可以使得當一些地方 type 不正確時產生紅色波浪 ex. 參數沒填入 type 時
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx" // jsx 必須依賴這個屬性才能夠使用在 typesccript 檔案中
},
"include": [
"src"
]
}
```