Categories
Tech

Tìm Hiểu TypeScript Và Áp Dụng Trong React

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).

TypeScript thừa hưởng cú pháp của JavaScript, vì vậy các lập trình viên có thể tiếp cận dễ dàng khi đã có các kiến thức cơ bản về JavaScript.

2. Ưu điểm và nhược điểm của TypeScript:

a. Ưu điểm:

  • Là mã nguồn mở: TypeScript là dự án mã nguồn mở nên bạn có thể sử dụng hoàn miễn phí, ngoài ra còn được cộng đồng hỗ trợ.
  • Dễ dàng phát triển dự án lớn: TypeScript được thiết kế để phát triển các dự án lớn.
  • Hỗ trợ các tính năng mới nhất của JavaScript: Bản chất của TypeScript là biên dịch tạo ra các đoạn mã JavaScript, nên nó đảm bảo sử dụng đầy đủ các kỹ thuật, tính năng mới nhất của JavaScript.
  • Hỗ trợ OOP mạnh: Về cơ bản JavaScript có hỗ trợ hướng đối tượng, nhưng khi áp dụng thì rất khó khăn do cách triển khai code không hề đơn giản như các ngôn ngữ bậc cao.
  • Cách tổ chức code rõ ràng: Code TypeScript trông gọn gàng và dễ nhìn hơn do được hỗ trợ các kỹ thuật mới nhất và lập trình hướng đối tượng.
  • Nhiều Framework lựa chọn: Nhiều JavaScript Framework đã dần khuyến khích sử dụng TypeScript để phát triển, ví dụ như AngularJS 2.0 và Ionic 2.0.

b. Nhược điểm:

  • Thêm một JS để học: Dù thừa hưởng cú pháp của JavaScript nhưng TypeScript vẫn là một dự án riêng biệt nên cũng có cú pháp riêng. Nhưng yên tâm là dễ học nhé.
  • Mã cồng kềnh: Bạn phải viết nhiều mã hơn và các chú thích bổ sung làm cho tệp TypeScript trở nên lớn và cồng kềnh hơn là một tệp JavaScript.
  • Thêm bước bổ sung – biên dịch: TypeScript không thể chạy trực tiếp trong chương trình, mà phải được biên dịch qua JavaScript. 
  • Không phải ngôn ngữ gõ tĩnh thực sự: Mặc dù phải xác định kiểu cho tất cả dữ liệu khi khai báo, nhưng TypeScript không phải ngôn ngữ gõ tĩnh thực sự bởi nó không chạy trực tiếp trong chương trình, khi được biên dịch sang JavaScript sẽ luôn có nguy cơ chuyển đổi thành một kiểu lạ.
3. Cài đặt:

TypeScript không thể chạy trực tiếp ngay trong trình duyệt mà chúng được biên dịch qua JavaScript bởi trình biên dịch thông qua npm. Vì vậy để làm việc với TypeScript, bạn phải cài đặt node.js và npm. 

Chạy lệnh sau để cài đặt:

npm install -g typescript

Để tạo file .js từ file .ts:

tsc fileName.ts

4. Cơ bản về TypeScript:

a. Types:

Các type cơ bản của TypeScript bao gồm: number, string, boolean, array, any, class, object, void. Cấu trúc để khai báo biến với TypeScript như sau:

var tên_biến: kiểu_trả_về = giá_trị_biến;
  • Number:
var height: number = 10;
  • String:
var name: string = “Nguyen Van A”;
  • Boolean:
var isCompleted: boolean = true;
  • Array:
var fruits: string[] = [“apple”, “organe”, “kiwi”];
var 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. 
var notSure: any = 10;

notSure = “Hello World!”; // hợp lệ
notSure = false; // hợp lệ

TypeScript sẽ bỏ qua việc kiểm tra type của biến khi được khai báo kiểu any và cho phép thực hiện bất kỳ operation.

notSure.foo().bar(); 
notSure[0];
  • 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

– Để tiếp tục tới giá trị được khai báo kiểu unknown, ta có thể sử dụng type-checking (kiểm tra kiểu của biến) để thực hiện các operation.

if (typeof unknownValue == 'string') {
    unknownValue = unknownValue.toString();
}

if (unknownValue instanceOf User) {
    name = unknownValue.getName();
}
  • Class: 
class User {
    name: string;
    constructor() {}

    setName (name: string) {
        this.name = name;
    }

    getName () {
        return this.name;
    }
}

var user: User = new User();
user.setName(“Van”);
var name: string = user.getName(); // name = “Van”;
  • Object:
var 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”);
}

b. Function:

  • TypeScript hỗ trợ kiểu trả ra của function và kiểu đầu vào của dữ liệu.
function add(x: number, y: number ): number {
    return x + y;
}

function greeting(name: string): string {
    return “Hello ” + name;
}
  • Khai báo giá trị mặc định của dữ liệu đầu vào.
function fullName(firstName: string, lastName: string = “Nguyen Van”): string {
    return firstName + “ “ + lastName;
}

fullName(“A”); // results = “A".
fullName(“A”, 12); // error, kiểu dữ liệu thứ 2 là string.
fullName(“B”, “Le Thi”);  // results = “B Le Thi".
  • Bỏ qua một hoặc vài dữ liệu đầu vào bằng cách thêm dấu ? sau tên biến.
function fullName(firstName: string, lastName?: string): string {
    if (lastName) {
        return firstName + “ “ + lastName;
    } else {
        return firstName;
    }
}

fullName(“A”); // results = “A".
fullName(“A”, “Le Thi”, “Nguyen Van”); // error, too many parameters.
fullName(“B”, “Le Thi”);  // results = “B Le Thi".
  • Rest Parameters: các dữ liệu này được gộp chung vào một biến Array.
function fullName(name: string, …restOfName: string[]): string {
    return firstName + “, “ + restOfName.join(“, ”);
}

fullName(“A”, “B”, “C"); // results = “A, B, C".
5. Áp dụng TypeScript trong React:

Như đã giới thiệu ở phần trước thì TypeScript hỗ trợ cho các Framework của JavaScript, trong đó có React. Vì vậy mình sẽ hướng dẫn cách dùng TypeScript với React:

Tạo ứng dụng React với TypeScript:

  • Nếu bạn dùng npm:

npm install create-react-app

create-react-app <name-project> template –typescript

  • hoặc nếu với yarn:

yarn add global create-react-app

yarn create react-app my-app –template typescript

a. Cách tạo Component:

Đây là cách viết một function component đơn giản của React: tạo file App.js

const App = () => {
    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo" />
                <h2>Hello World!</h2>
           </header>
        </div>
    );
};

Để khai báo một function component kết hợp TypeScript trong React, bạn tạo file App.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é.
const App: React.FC = () => {
    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo" />
                <h2>Hello World!</h2>
            </header>
        </div>
    );
};

Kết quả:

b. State:

Dưới đây là một class component cơ bản của React. Tạo file App.js:

const App: React.FC = () =>  {
    const [user, setUser] = useState({name: 'Van', age: 23});

    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <h2>Hello {user.name}!</h2>
            </header>
        </div>
    );
};

Để khai báo state với TypeScript, bạn cần tạo file với đuôi .tsx: App.tsx

interface States {
    name: string,
    age: number
}

const App: React.FC = () =>  {
    const [user, setUser] = useState<States>({name: 'Van', age: 23});

    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <h2>Hello {user.name}!</h2>
            </header>
        </div>
    );
};

Kết quả:

  • Trước tiên mình khai báo một interface với tên States, và tạo các biến state lần lượt là name và age với kiểu tương ứng.

Khi tạo Component, mình sẽ khai báo như sau:

const [user, setUser] = useState<States>({name: 'Van', age: 23});

Lưu ý:
– Khi tạo interface cho state, bạn cần phải khai báo đầy đủ các biến state sẽ dùng trong Component. Và những biến khai báo ở trên phải chắc chắn được sử dụng.

Ví dụ báo lỗi:

interface States {
    name: string,
    age: number
}

const App: React.FC = () =>  {
    const [user, setUser] = useState<States>({name: 'Van'}); // error here

    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <h2>Hello {user.name}!</h2>
            </header>
        </div>
    );
};

Ở ví dụ trên, state mình khai báo trong interface gồm name và age, nhưng trong Component chỉ có name, thì nó sẽ báo lỗi. Nhưng nếu state này được sử dụng nhiều nơi trong project và bạn không muốn khai báo lại nhiều lần thì có thể khai báo state như sau:

interface States {
    name: string,
    age?: number, // thêm dấu ? sau tên biến nhé
}

c. Props:

Trong ví dụ  về Props mình sẽ tạo một Component con nhận props từ Component cha.

Trong Function Component, props truyền vào như một thuộc tính của một function.

interface Props {
    isStudent: boolean
}

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

Để khai báo props trong TypeScript, bạn cũng làm tương tự như state là tạo một interface, truyền vào Component và khai báo kiểu của props.

interface Props {
    isStudent: boolean
}

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

App.tsx:

const App: React.FC = () =>  {
    const [user, setUser] = useState<States>({name: 'Van'});

    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <h2>Hello {user.name}!</h2>
                <SubTextJS isStudent={false} />
            </header>
        </div>
    );
};

Kết quả:

Ví dụ báo lỗi: Khi khai báo kiểu Props ở component con, TypeScript sẽ báo ở component cha đang sử dụng sai kiểu truyền vào cho component con.

const App: React.FC = () =>  {
    const [user, setUser] = useState<States>({name: 'Van'});

    return (
        <div className="App">
            <header className="App-header">
                <img src={logo} className="App-logo" alt="logo"/>
                <h2>Hello {user.name}!</h2>
                {/* error here */}
                {/* kiểu của props isStudent không phải là string */}
                <SubText isStudent={'false'} />
            </header>
        </div>
    );
};

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

interface Todo {
    id: number;
    title: string,
    completed: boolean
}

interface ListTodo {
    list: Todo[], // ở đây khai báo list là 1 mảng gồm các Todo,
    total: number
}

Bạn có thể extends một interface như sau:

interface NewTodo extends Todo {
    userId: number
}
// Lúc này NewTodo sẽ có bốn thuộc tính: id, title, completed và userId.
6. Lời Kết:

TypeScript kết hợp với React rất tốt, giúp code React chặt chẽ hơn, dễ dàng quản lý trong những dự án lớn. Trên đây mình chỉ giới thiệu cơ bản về TypeScript và cách áp dụng trong React. Hẹn các bạn ở bài viết sau, chúng ta sẽ cùng tìm hiểu chi tiết hơn. 😉

7. Tài liệu tham khảo:

Tìm hiểu TypeScript và kiến thức cơ bản

TypeScript Overview

The Good and the Bad of TypeScript