typescript cơ bản trong react

Hướng dẫn TypeScript Trong React

2022-03-08 2359 lượt xem

1.TypeScript là gì?

TypeScript là một dự án mã nguồn mở được phát triển bởi Microsoft, được xem là phiên bản nâng cao của JavaScript. Vì nó được bổ sung tùy chọn kiểu tĩnh và các lớp hướng đối tượng, nó bao hàm cả ECMAScript 2015 (ES6).

Ưu điểm:

  • Là mã nguồn mở
  • Dễ dàng phát triển dự án lớn
  • Hỗ trợ các tính năng mới nhất của JavaScript
  • Hỗ trợ OOP mạnh
  • Cách tổ chức code rõ ràng
  • Nhiều Framework lựa chọn

Nhược điểm

  • Phải học thêm 1 loại js si da mới
  • Mã cồng kềnh
  • Thêm bước bổ sung – biên dịch
  • Không phải ngôn ngữ gõ tĩnh thực sự

Cài đặt typescript

# Chạy lệnh sau để cài đặt:
npm install -g typescript
# Để tạo file .js từ file .ts:
tsc fileName.ts

Cơ bản về TypeScript

Các type cơ bản của TypeScript bao gồm: number, string, boolean, array, any, class, object, void

// kiểu số
const height: number = 10
/// kiểu chuỗi
const name: string = 'Nguyen Van A'
// kiểu Boolean
const isCompleted: boolean = true
// kiểu Array
const fruits: string[] = ['apple', 'organe', 'kiwi']
const ages: number[] = [10, 11, 12, 13, 14]
// Any: là kiểu mà bạn có thể gán bất kỳ giá trị nào cho biến.
let notSure: any = 10
notSure = 'Hello World!' // hợp lệ
notSure = false // hợp lệ
// unknown: Cũng giống như any, unknown cho phép nhận bất kỳ giá trị cho biến. Nhưng không cho phép operation nào.
let unknownValue: unknown
unknownValue.foo().bar() // ERROR
unknownValue[0] // ERROR

// kiểu class
class User {
  name: string
  constructor() {}

  setName(name: string) {
    this.name = name
  }
  getName() {
    return this.name
  }
}
const user: User = new User()
user.setName('van')
let name: string = user.getName() // name = “Van”;

// kiểu Object
const people: { name: string; age: number } = {
  name: 'van',
  age: 23,
}
// Void: cũng giống như any nhưng được sử dụng là đầu ra của hàm.\
function warning(): void {
  alert('This is a warning message')
}

Áp dụng TypeScript trong React

Để khai báo một function component kết hợp TypeScript trong React, bạn tạo file Index.tsx, và thêm: : React.FC sau tên component. 

  • FC là viết tắt cho Function Component, khi thêm : React.FC thì sẽ hiểu type của App chính là một Function Component của React.
  • Để viết được cú pháp của TypeScript bạn phải tạo file với đuôi .ts hoặc .tsx (cho file chứa html) nhé.
 import React from 'react'

const Home: React.FC = () => {
  return (
    <div className="Home">
      <header className="Home-header">
        <h2>Hello Component Typescript!</h2>
      </header>
    </div>
  )
}
export default Home

Khi sử dụng state trong react typescript

import React, { useState } from 'react'

interface States {
  name: string
  age: number
}

const Home: React.FC = () => {
  const [user, setUser] = useState<States>({ name: 'Hùng đẹp trai', age: 27 })

  const changeUser = () => {
    setUser({ ...user, age: user.age + 1 })
  }
  return (
    <div className="Home">
      <header className="Home-header">
        <h2>
          Hello {user.name} - {user.age}!
        </h2>
      </header>
      <button onClick={changeUser}>change user</button>
    </div>
  )
}
export default Home

Mô tả là đầu tiên bạn khai báo 1 interface của typescript rằng bạn có 1 States dạng object có 2 property nameage.

Dòng const [user, setUser] = useState<States>({ name: 'Hùng đẹp trai', age: 27 }) đang khai báo là hàm useState sử dụng kiểu dữ liệu là States được khai báo trên với initial ban đầu là  { name: 'Hùng đẹp trai', age: 27 }

Chú ý: Khi bạn đã khai báo như vậy xong, giả sử bạn nghịch nghịch bạn thêm trong useState<States>({ name: 'Hùng đẹp trai', age: 27, thuocTinhMoi: "Chế 1 Thuộc tính mới cho state" }) => lập tức văng lỗi ngay! hoặc bạn setUser mà name sai kiểu dữ liệu cũng văng lỗi luôn.

Tương tự bạn cũng có thể khai báo typescript cho props ví dụ như sau:

import React from 'react'

interface Props {
  isStudent: boolean
}
const TextModify: React.FC = (props) => {
  return (
    <div>
      {props.isStudent ? (
        <p>You are a student.</p>
      ) : (
        <p>You aren't a student.</p>
      )}
    </div>
  )
}

const Home: React.FC = () => {
  return (
    <div className="Home">
      <header className="Home-header">
        <h2>Hello</h2>
        <TextModify isStudent={true} />
      </header>
    </div>
  )
}
export default Home

Trên giao diện thì chạy được: 

 

Nhưng IDE không thích điều này:

Việc này do code của bạn không khai báo minh bạch cho component TextModify là props là thể hiện của 1 interface nào. Điều đó làm nó hoang mang báo bạn như thế, chứ khi bạn edit: 
const TextModify: React.FC = (props) => { 
chuyển thành 
const TextModify: React.FC<Props> = (props) => {
khi đó props sẽ là 1 thể hiện của Props được định nghĩa trước đó nên sẽ hết báo đỏ

Một số quy tắc nên nhớ trong typescript

Khai báo dữ liệu với kiểu là interface trong React:

interface PropsUser {
  name: boolean
}
interface StateListUser {
  users: PropsUser[]
}

Optional properties -Optional chaining

Đôi khi trong code của chúng ta cần khai báo 1 property mà có cũng được không có cũng được thì chúng ta gọi thuộc tính đó là optional. Chúng ta dùng toán tử dấu: "?" để làm điều này. ví dụ: (bạn để ý trường email?: string trong ví dụ dưới

import React from 'react'

interface PropsUser {
  name: string
  phone: string
  email?: string
}

const user1 = {
  name: 'nguyễn văn tèo',
  phone: '2343242432',
  email: 'teo_khoai_to@gmail.com',
}
const user2 = { name: 'nguyễn văn tí', phone: '2343242432' } // không có email vẫn work

const TextModify: React.FC<PropsUser> = (props) => {
  return (
    <div>
      {props.name} - {props.phone} {props?.email}
    </div>
  )
}

const Home: React.FC = () => {
  return (
    <div className="Home">
      <header className="Home-header">
        <h2>Hello</h2>
        <TextModify {...user1} />
        <TextModify {...user2} />
      </header>
    </div>
  )
}
export default Home

kết quả: 

 

Trong đoạn code phía dưới mình có sử dụng kỹ thuật: Optional chaining. Cái khúc props?.email là email có thể có hoặc không. Rồi lỡ như không có mà mình để props.email thì có khả năng bị crash react. Nên mình dùng thêm dấu "?." để check nếu email không có thì return undefine

Extend interface trong TypeScript

Khi làm việc với typescript đôi khi bạn tạo ra interface thứ nhất là Button xong, lỡ bạn muốn kế thừa lại các thuộc tính của Button nhưng có thêm vài thuộc tính khác thì làm sao? => dùng từ khoá extends!

interface Button {
  text: string
  onClick: () => void
}

const buttonLogin: Button = {
  text: 'login',
  onClick: () => {
    console.log('bấm login')
  },
}
// phát sinh ra IconButton cũng giống Button nhưng có icon

interface IconButton extends Button {
  icon: string
}

const iconLoginBtn: IconButton = {
  icon: 'ahihi',
  text: 'login',
  onClick: function (): void {
    console.log('bấm icon button nè')
  },
}

Implement interface trong TypeScript

adadssa

Interface declaration merging

mở rộng interface : chi tiết ở đây: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

Tạm hiểu là 1 interface trong typescript có khả năng add thêm thuộc tính cho cả cái interface cũ. Điểm lợi thế của việc này nó giống với bạn define 1 kiểu dữ liệu ban đầu nhưng đồng đội nhà bạn sau này sài tự dưng lòi ra kiểu logic y chang như cần thêm property. Ví dụ:

interface Box {
  height: number;
  width: number;
}
interface Box {
  scale: number;
}
let box: Box = { height: 5, width: 6, scale: 10 };

Thuộc tính readonly (chỉ đọc )

Khi bạn muốn define 1 properties mà chỉ có setting init 1 lần không thể ghi đè thì bạn dùng thuộc tính readonly trong typescript. Ví dụ như sau: 

interface Point 
{ 
    readonly x: number; 
    readonly y: number; 
}