Giới thiệu về FlowJS
Bài đăng này đã không được cập nhật trong 5 năm
1. Mở đầu
Đối với các bạn mới tiếp cận với Javascript hoặc đã làm việc với nó từ lầu thì đều biết được nó là ngôn ngữ dạng dynamic và weak type. Nếu bạn không biết nó nghĩa là gì thì có thể tham khảo tại đây. Tuy nhiên không giống như những ngôn ngữ có dạng tương tự như PHP, Python mà Javascript lại sở hữu một hệ thống typing vô cùng ảo diệu và biến hóa khôn lường dẫn tới nhiều tính huống giở khóc giở cười khi làm việc với nó. Nếu muốn hiểu sâu hơn về sự ảo diệu này thì bạn có thể đọc ở đây . Vì thế hôm nay mình sẽ hướng dẫn các bạn sử dụng một thư viện hỗ trợ cho việc kiểm tra loại dữ liệu hay còn gọi là static type checker
cho Javascript đó chính là FlowJS một thư viện được phát triển bởi Facebook
.
2. Cài đặt
Để hỗ trợ cho các bạn trong việc nắm được nội dung cơ bản của bài viết thì trước hết chúng ta sẽ setup 1 project đơn giản để trải nghiệm FlowJS
.
- Đầu tiên bạn cần chắc rằng máy của mình đã được cài
NodeJS
,npm
vàYarn
. - Tiếp đó chúng ta sẽ tạo 1 folder mới sau đó di chuyển vào folder đó bằng Terminal của bạn.
- Tiếp đó ta sẽ khởi tạo một project với lệnh:
$ npm init
Sau đó bạn nhập các thông tin cần thiết hoặc có thể bỏ qua và ấn enter liên tục cho đến khi tạo ra file package.jon
- Tiếp đến ta sẽ cài đặt folder
node_modules
với lệnh:
$ yarn install
Đợi cho quá trình tải các package thành công ta sẽ tiếp tục tạo thêm một folder mới đặt tên là src/
và một file index.js
nằm trong folder này. Trong file package.json
đã tạo ra trước đó bạn cần sửa lại phần main
để trỏ đến file index.js
nói trên
{
"name": "flows",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
- Tiếp theo chúng ta sẽ tiến hành cài đặt thêm
Babel
để hỗ trợ việc complie code với lệnh:
$ yarn add --dev babel-cli babel-preset-flow
- Tiếp đến ta tạo một file
.babelrc
với nội dung như sau:
{
"presets": ["flow"]
}
- Cuối cùng chúng ta sẽ cài đặt
Flow
với lệnh:
$ yarn add --dev flow-bin
- Trước khi để có thể chạy được
Flow
ta cần tạo file config cho nó với lệnh:
$ yarn flow init
Lệnh trên sẽ tạo cho chúng ta một file có tên là .flowconfig
chưa những config mà bạn muốn thêm vào. Để phục vụ cho việc demo đơn giản thì ta chỉ cần sửa lại file đó như sau:
[ignore]
[include]
src
[libs]
[lints]
[options]
[strict]
[include] src
là cài đặt folder mà Flow sẽ kiểm tra khi ta chạy lệnh. Quá trình cài đặt đến đây là kết thúc bây giờ chúng ta sẽ bắt đầu khám phá Flow
.
3. Chạy thử flows
Đầu tiên trong file src/index.js
mà chúng ta đã tạo ở trên ta sẽ thêm nội dung vào như sau:
// @flow
function sayHello(name: string): void {
console.log(`Hello ${name}`);
}
sayHello('FlowJS');
Mặc dù chúng ta đã config lại flow sẽ tiến hành kiểm tra type trong folder src/
tuy nhiên Flow sẽ chỉ tiến hành check các file bắt đầu bằng:
// @flow
Hoặc
/* @flow */
Bây giờ bạn có thể gõ lệnh:
$ yarn flow status
Sẽ thu được kết quả sau trên terminal:
$ yarn flow status
yarn run v1.7.0
$ /node_modules/.bin/flow status
No errors!
Done in 0.17s.
Vậy là Flow
vừa tiến hành check type cho file index.js
của chúng ta và không phát hiện lỗi nào cả. Ở đây cú pháp của FlowJS
sẽ có dạng variableName: type
hay tên biến sau đó mới đến kiểu dữ liệu mà ta muốn định nghĩa cho biến đó.
Nếu bạn thử sửa lại đoạn code trên và thay vì truyền vào string
cho hàm sayHello()
thì ta truyền thử số 1 rồi chạy lại lệnh yarn flow status
sẽ thu được kết quả như sau:
$ yarn flow status
yarn run v1.7.0
$ /node_modules/.bin/flow status
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/index.js:6:10
Cannot call sayHello with 1 bound to name because number [1] is incompatible with string [2].
[2] 2│ function sayHello(name: string): void {
3│ console.log(`Hello ${name}`);
4│ }
5│
[1] 6│ sayHello(1);
7│
Found 1 error
error Command failed with exit code 2.
Đây chính là kết quả thu được trong trường hợp code của bạn gặp lỗi về kiểu dữ liệu. Đồng thời nếu bạn sử dụng VSCode
hoặc Sublimetext
hay bất cứ text-editor hay IDE mà bạn ưa thích đều có cách hỗ trợ cho việc phát hiện từ ngay khi bạn code. Của mình khi dùng VSCode
với trường hợp truyền số vào hàm sayHello()
thì sẽ có lỗi như sau:
Đến đây chúng ta đã được sử dụng thử tính năng của FlowJS
tiếp sau đây chúng ta sẽ đi vào các khái niệm của nó.
4. Các kiểu dữ liệu cơ bản
a. Primitive Types
Mặc định Flows
sẽ hỗ trợ chúng ta kiểm tra các kiểu dữ liệu dạng Primitive
tương tự với trong Javascript thông thường như sau:
- Boolean
// @flow
function acceptBoolean(myVar: boolean) {
// ...
}
acceptBoolean(true); // Ok
acceptBoolean(false); // OK
acceptBoolean('foo'); // Error
- Number
// @flow
function acceptNumber(myVar: number) {
// ...
}
acceptNumber(1); // Ok
acceptNumber(3.14); // OK
acceptNumber('foo'); // Error
- String
// @flow
function acceptsString(myVar: string) {
// ...
}
acceptsString('hello'); // Ok
acceptsString(true); // Error
acceptsString(1); // Error
- Null
// @flow
function acceptsNull(myVar: null) {
// ...
}
acceptsNull(null); // Ok
acceptsNull(undefined); // Error
acceptsNull(true); // Error
- Void (undefined): Kiểu dữ liệu dạng
undefined
trong Javascript sẽ được chuyển thành kiểuvoid
trongFlowJS
// @flow
function acceptsUndefined(myVar: void) {
// ...
}
acceptsUndefined(undefined); // Ok
acceptsUndefined(); // Ok
acceptsUndefined(true); // Error
Ngoài kiểu dữ liệu null
và void
nói trên các kiểu dữ liệu còn lại ta đều có thể truyền tham số mặc định cho nó với dạng như sau:
// @flow
function acceptsString(myVar: string = 'default') {
// ...
}
Trong trường hợp bạn muốn hàm của mình có tham số truyền vào dạng string (hoặc boolean, number) hoặc không truyền vào gì cũng được thì có thể sử dụng cú pháp như sau:
// @flow
function acceptsString(myVar?: string) {
// ...
}
Hàm trên sẽ nhận vào 2 kiểu dữ liệu được tính là hợp lệ đó là string
và undefined
.
b. Literal Types
Ngoài việc check kiểu dữ liệu thuộc dạng Primitive
như trên Flow
cũng có thể kiểm tra các kiểu dữ liệu thuộc dạng hằng số như sau:
// @flow
function acceptsTen(value: 10) {
//
}
acceptsTen(10) // Ok
acceptsTen(2) // Error
acceptsTen('foo') // Error
Không những check được một hằng số như trên Flow
cho phép bạn chấp nhận một nhóm các hằng số như sau:
// @flow
function status(status: 'success' | 'error' | 'pending') {
//
}
status('success') // Ok
status('pending') // Ok
status('warning') // Error
c. Mixed Types
Giống như ví dụ ở ngay trên bên trên, ngoài việc kiểm tra đầu vào là một nhóm các hằng số, Flow
cũng cho phép bạn kiểm tra đầu vào là một trong các kiểu dữ liệu bạn mong muốn như sau:
// @flow
function acceptStringAndNumber(myVar: string | number) {
//
}
acceptStringAndNumber(10) // Ok
acceptStringAndNumber(3.14) // Ok
acceptStringAndNumber('foo') // Ok
acceptStringAndNumber(true) // Error
Trường hợp bạn muốn nhận giá trị đầu vào là kiểu dữ liệu bất kì thì có thể sử dụng luôn kiểu mixed
:
// @flow
function acceptAnything(myVar: mixed) {
//
}
acceptAnything(10) // Ok
acceptAnything(3.14) // Ok
acceptAnything('foo') // Ok
acceptAnything(true) // Ok
acceptAnything(null) // Ok
acceptAnything() // Ok
d. Maybe Types
Tương tự với một ví dụ mà mình nói đến ở phần Primitive
:
// @flow
function acceptsString(myVar?: string) {
// ...
}
Ví dụ trên sẽ chỉ nhận vào kiểu dữ liệu là string
hoặc void
. Tuy nhiên khi bạn nếu giá trị truyền vào của bạn có thể là cả null
thì ta có thể sửa lại như sau:
// @flow
function acceptsString(myVar: ?string) {
// ...
}
Lúc này biến myVar
có thể là string
, null
hoặc void
.
e. Function Return Types
Ngoài việc kiểm tra kiểu dữ liệu cho các biến và tham số truyền vào hàm, Flow
còn có thể giúp ta kiểm tra kiểu dữ liệu trả về của hàm đó. Việc này giúp ta tránh được tình trạng vô tình trong quên trả về kiểu dữ liệu cần thiết cho hàm tại một lệnh rẽ nhánh nào đó. Ví dụ:
// @flow
function method(): boolean {
if (Math.random() > 0.5) {
return true;
}
}
Đoạn code trên khi chạy qua Flow
sẽ báo lỗi vì Flow
sẽ tự động phát hiện được nếu rơi vào trường hợp khác if sẽ không có kiểu dữ liệu nào được trả về cả dẫn tới vi phạm kiểu dữ liệu mong muốn là boolean
.
f. Non Primitive Types
Ngoài các Primitive types
đã nói ban đầu thì tất nhiên Flows
cũng hỗ trợ chúng ta kiểm tra các loại dữ liệu như Array
, Object
, Tupple
.
- Với
Array
cú pháp sẽ như sau:
// @flow
function acceptArray(myVar: Array<string>) {
//
}
// Hoặc
function acceptArray(myVar: string[]) {
//
}
acceptArray(['foo', 'bar']) // Ok
acceptArray([1, 'baz]) // Error
acceptArray([true, 'abc') // Error
Không chỉ có thể sử dụng Array
với đơn kiểu dữ liệu như trên mà bạn cũng có thể dùng dưới các dạng như Primitive Types
:
// @flow
let arr1: Array<mixed> = [1, true, 'string'];
let arr2: ?number[] = [1, 2]
let arr3: ?string[] = null
- Với các
Object
ta cũng có thể kiểm tra các thuộc tính của nó có đúng kiểu dữ liệu như ta mong muốn không:
// @flow
var obj: { foo: boolean } = { foo: true };
var obj2: {
foo: number,
bar: boolean,
baz: string,
} = {
foo: 1,
bar: true,
baz: 'three',
};
- Còn
Tupple
cũng có dạng giốngArray
nhưng số lượng phần tử của nó được cố định cùng với kiểu dữ liệu của từng phần tử theo thứ tự tương ứng:
// @flow
let tuple: [number, boolean, string] = [1, true, 'three'];
tuple[0] = 20 // Ok
tuple[1] = 'bar' // Error
tuple[2] = 'fooo' // Ok
Lưu ý khi bạn cập nhập giá trị của các phần tử trong Tuple
thì cũng cần phải đúng kiểu dữ liệu đã định nghĩa nếu không sẽ báo lỗi
5. Kết bài
Trên đấy là bài giới thiệu của mình về việc sử dụng Flow
và một số kiểu dữ liệu cơ bản trong nó. Nếu bạn muốn tìm hiểu sâu hơn về cái types khác thì hãy lên docs của Flow
ở đây để có thể tìm hiểu. Cảm ơn các bạn đã đọc bài
All rights reserved