- TypeScript là gì và tại sao nên dùng TypeScript thay JavaScript?
TypeScript là superset của JavaScript có kiểu tĩnh, biên dịch ra JavaScript thuần. Cùng đoạn đó trong JavaScript chạy bình thường và trả về '0102' — một bug âm thầm chỉ lộ ra khi người dùng gặp. Bốn lợi ích, xếp theo mức tác động…
- Type annotation trong TypeScript là gì?
Type annotation là khai báo kiểu tường minh cho biến, parameter, return value: let name: string = 'John'. TypeScript cũng có type inference tự suy luận kiểu từ giá trị gán. Annotation thường chỉ cần cho function parameters, return types, và khi inference không đủ…
- any, unknown và never khác nhau như thế nào?
Ba kiểu ở ba vị trí đối lập nhau trong hệ thống kiểu. Gán giá trị vào Gán ra biến khác An toàn ------------ any mọi thứ mọi thứ không unknown mọi thứ chỉ sau khi thu hẹp có never không gì mọi thứ —…
- Union types và intersection types là gì?
A B là hoặc, A & B là và. Điểm hay nhầm — union thu hẹp cái dùng được, intersection mở rộng: Muốn dùng thuộc tính riêng của union thì phải thu hẹp kiểu trước (typeof, in, discriminated union). Hai đặc điểm của intersection hay…
- Literal types trong TypeScript là gì?
Literal type là kiểu chỉ nhận đúng một giá trị cụ thể. Dùng thay enum mà không sinh code lúc chạy: Lưu ý — TypeScript mở rộng kiểu khi dùng let: Giữ literal bằng as const: Chốt: literal type là nền tảng của discriminated union…
- Type narrowing là gì? Các cách narrow type trong TypeScript?
Type narrowing là thu hẹp type trong code branch dựa trên kiểm tra. TypeScript tự động narrow trong if/else, switch, ternary.
- as keyword (type assertion) là gì? Khi nào dùng?
as ghi đè suy luận kiểu của TypeScript lúc biên dịch, và không kiểm tra gì lúc chạy. Hai trường hợp dùng hợp lý: 1. DOM — TypeScript chỉ biết HTMLElement, bạn biết cụ thể hơn. 2. as const — giữ literal type, đây là…
- Non-null assertion operator (!) là gì?
! nói với TypeScript rằng giá trị chắc chắn không phải null/undefined — và cũng không kiểm tra gì lúc chạy. Các cách thay thế, xếp theo mức an toàn giảm dần: Còn một dạng khác của ! — definite assignment assertion trên khai báo…
- Tuple type trong TypeScript là gì?
Tuple là array với số lượng và kiểu phần tử cố định. Phần tử có thể có tên. Hỗ trợ optional (?) và rest elements. Thường dùng cho function return nhiều giá trị, CSV rows, React useState.
- Enum trong TypeScript là gì? Numeric vs string enum khác nhau thế nào?
Enum khai báo tập hợp named constants. Numeric enum tự động assign 0,1,2... có reverse lookup nhưng gây footgun (Direction[0] = 'Up'). String enum cần gán tường minh, dễ debug hơn, không có reverse lookup.
- satisfies operator trong TypeScript là gì?
satisfies (TS 4.9) kiểm tra type mà không mở rộng type declaration. Khác as: satisfies vẫn infer type cụ thể nhất có thể và báo lỗi nếu không match. Ví dụ: const config = {...} satisfies Config - TS check config đúng Config nhưng giữ…
- const assertion (as const) là gì?
as const biến values thành readonly literal types cụ thể nhất. Array thành readonly tuple, object properties thành readonly literal types. Ví dụ: const dirs = ['left', 'right'] as const tạo type readonly ['left', 'right'] thay string[]. Hữu ích để tạo strongly-typed constants.
- TypeScript strict mode bao gồm những gì?
"strict": true bật một nhóm cờ kiểm tra chặt cùng lúc: Hai cờ có tác động lớn nhất: useUnknownInCatchVariables (TS 4.4) hay gây bối rối khi nâng cấp dự án cũ: Chuyển dự án JavaScript sang TypeScript thì bật dần, không bật hết một lần:…
- interface và type alias khác nhau như thế nào? Khi nào dùng cái nào?
Cả hai đều mô tả shape (cấu trúc) của object; khác nhau ở những gì làm được ngoài object và khả năng gộp khai báo. interface type --------- Mô tả object có có Union / tuple / conditional không có Gộp khai báo (merging) có…
- Cách extend interface và type trong TypeScript?
Interface: interface Child extends Parent { ... } và extends nhiều: extends A, B. Type: type Combined = A & B (intersection). Interface có thể extend type và ngược lại. extends kiểm tra compatibility (không thể re-declare incompatible property), còn & intersection merge tất cả.
- Index signature trong TypeScript là gì?
Index signature cho phép object có keys không biết trước. Tất cả explicit properties phải compatible với index signature type.
- Optional properties (?) và readonly properties là gì?
Optional property (prop?: Type) có thể có hoặc không, type là Type undefined khi access. Khác với prop: Type undefined — cái sau vẫn yêu cầu key có mặt khi tạo object. readonly property không thể reassign sau khởi tạo (chỉ compile time). Readonly<T làm…
- Discriminated unions là gì? Tại sao hữu ích?
Discriminated union là union trong đó mỗi member có common literal property (discriminant). TypeScript narrow type tự động khi check discriminant. Giúp type-safe handling cases khác nhau, TypeScript sẽ báo lỗi nếu thiếu case.
- Module augmentation là gì?
- Recursive types trong TypeScript là gì?
TypeScript hỗ trợ recursive type aliases. Hữu ích cho tree structures, nested JSON, linked lists. Interface luôn hỗ trợ recursive (vì là named type), type alias cũng hỗ trợ từ TS 3.7.
- Branded types (nominal types) trong TypeScript là gì?
- Excess property checking trong TypeScript là gì?
TypeScript kiểm tra extra properties khi assign object literal trực tiếp vào typed variable. Nhưng assign qua biến trung gian không bị check — đây là behavior khá bất ngờ. Behavior này giúp phát hiện typos trong config objects.
- Generics trong TypeScript là gì? Tại sao cần thiết?
Generics cho phép tạo components (functions, classes, interfaces) hoạt động với nhiều kiểu dữ liệu mà vẫn type-safe. Thay dùng any, dùng type parameter <T. Tái sử dụng code mà không mất type information.
- Generic constraints (extends) trong TypeScript là gì?
Constraints giới hạn type parameter phải extend một type cụ thể, ngăn dùng với types không compatible.
- keyof operator là gì?
keyof T trả về union type của tất cả keys của T: keyof {a: number, b: string} cho ra 'a' 'b'. Dùng với generics để type-safe property access: function get<T, K extends keyof T(obj: T, key: K): T[K] đảm bảo key tồn tại và return…
- Mapped types trong TypeScript là gì?
- Conditional types trong TypeScript là gì?
- infer keyword trong conditional types là gì?
- Template literal types trong TypeScript là gì?
- Recursive conditional types là gì?
- Utility type `Parameters<T>` và `ConstructorParameters<T>` là gì?
Hai utility type trích ra danh sách tham số dưới dạng tuple. Bên trong cả hai đều dùng infer: Công dụng thực tế nhất — bọc một hàm mà không phải khai lại signature: Lấy một tham số riêng lẻ bằng chỉ số: Lưu ý:…
- Generic functions với multiple type parameters như thế nào?
Hàm có thể có nhiều type params. Inference hoạt động độc lập cho mỗi param. Đặt tên rõ ràng (TKey, TValue) thay vì chỉ T, U, V khi có nhiều params.
- `Partial<T>` và `Required<T>` là gì?
Partial<T làm tất cả properties của T thành optional. Required<T làm tất cả optional thành required. Cả hai chỉ shallow.
- `Record<K, V>` là gì? Khác index signature như thế nào?
Record<Keys, Value tạo object type với specific keys và value type. Khác index signature: Keys có thể là specific union (yêu cầu tất cả keys có mặt, không optional). Rõ ràng hơn và type-safe hơn index signature.
- `Pick<T, K>` và `Omit<T, K>` là gì?
Pick<T, K tạo type chỉ với subset of properties K từ T: Pick<User, 'id' 'name' chỉ giữ lại id và name. Omit<T, K là ngược lại: tạo type với tất cả properties trừ K, ví dụ Omit<User, 'password' để không lộ mật khẩu trong response.…
- `Exclude<T, U>` và `Extract<T, U>` là gì?
Exclude<T, U loại bỏ khỏi union T những types có thể assign cho U: Exclude<'a''b''c', 'a' cho ra 'b''c'. Extract<T, U ngược lại — giữ lại những types assign được cho U: Extract<stringnumberboolean, stringnumber cho ra stringnumber. Ví dụ thực tế: type NonString<T = Exclude<T,…
- `ReturnType<T>` và `Awaited<T>` là gì?
ReturnType<T lấy return type của function T mà không cần khai báo lại: type Result = ReturnType<typeof fetchUser tự cập nhật khi hàm thay đổi. Awaited<T unwrap Promise đệ quy: Awaited<Promise<string cho ra string, Awaited<Promise<Promise<number cho ra number. Kết hợp cả hai cho async functions:…
- `NonNullable<T>` là gì?
NonNullable<T loại bỏ null và undefined khỏi type T: NonNullable<string null undefined cho ra string. Tương đương với Exclude<T, null undefined. Hay dùng sau khi đã kiểm tra null ở runtime nhưng TypeScript vẫn chưa tự narrow được — ví dụ kết quả từ Array.find()…
- `Readonly<T>` và `ReadonlyArray<T>` là gì?
Readonly<T làm tất cả properties của T thành readonly (shallow). ReadonlyArray<T là array không thể modify (push, pop, sort không available). Dùng với as const, Redux state, functional programming. Deep readonly cần custom type: DeepReadonly<T với recursive mapped type.
- Hãy implement `Partial<T>` từ đầu để hiểu cách hoạt động.
Dùng mapped type iterate qua tất cả keys của T, thêm ? để optional. Hiểu cách này giúp tạo custom utility types bất kỳ.
- Deep partial và deep readonly type tạo như thế nào?
- Type guards là gì? Các loại type guards trong TypeScript?
Type guards thu hẹp type trong code branch. Loại: 1) typeof, 2) instanceof, 3) in operator, 4) equality, 5) user-defined (function với return type is Type), 6) assertion functions.
- User-defined type guards (type predicates) là gì?
Function type với return type param is Type. Khi function return true, TS narrow type của param. Nguy hiểm: TS tin type predicate hoàn toàn, implementation sai sẽ gây runtime bug mà không có compile error.
- Decorators trong TypeScript là gì?
- Decorator metadata và reflect-metadata là gì?
- Function overloads trong TypeScript là gì?
- Declaration files (.d.ts) là gì?
Declaration files chứa type declarations không có implementation (ambient declarations). Dùng để type third-party libraries không viết bằng TS. @types/ packages trên npm. Tự viết .d.ts khi cần declare types cho JS code hoặc global variables.
- tsconfig.json các options quan trọng nhất là gì?
Trong tsconfig.json, strict: true là option quan trọng nhất vì nó bật toàn bộ strict type-checking bao gồm strictNullChecks, noImplicitAny và strictFunctionTypes. target xác định phiên bản ES output (ví dụ ES2020), module chọn hệ thống module (ESNext, CommonJS), và moduleResolution quyết định cách TypeScript…
- Conditional types với distributive behavior là gì? Cách disable?
- TypeScript với React: generics trong components là gì?
- TypeScript với React: typing hooks như thế nào?
useState: useState<Type(init) khi init không đủ thông tin. useRef: useRef<HTMLInputElement(null) cho DOM refs, useRef<number(0) cho mutable values (không trigger re-render). useReducer: type actions với discriminated unions.
- TypeScript với React: typing events là gì?
React.ChangeEvent<HTMLInputElement cho onChange, React.MouseEvent<HTMLButtonElement cho onClick, React.FormEvent<HTMLFormElement cho onSubmit. Nếu không nhớ chính xác: hover lên event trong IDE, hoặc dùng React.SyntheticEvent rộng hơn.
- Assertion functions trong TypeScript là gì?
- Tại sao TypeScript dùng structural typing thay nominal typing?
- Discriminated unions vs class hierarchy khi nào dùng cái nào?
- Exhaustiveness checking trong TypeScript là gì?
- Path aliases trong TypeScript (paths config) là gì?
paths trong tsconfig.json map import paths để tránh relative paths dài. Cần configure cả bundler vì TS compiler chỉ handle types, không transform imports.
- Type-only imports và exports là gì?
- TypeScript performance: tại sao type checking có thể chậm và cách cải thiện?
- Trong dự án đang lẫn lộn `type` và `interface`, bạn chốt quy ước dùng cái nào cho trường hợp nào?
Cả hai mô tả được shape của object và gần như thay thế nhau được, nên chọn theo khả năng riêng của từng loại chứ không theo sở thích. Dùng interface khi: - Mô tả object/class contract mà người khác có thể mở rộng —…
- Bật `strictNullChecks` trên một codebase cũ thì hay nổ ra những lỗi nào? Sửa theo hướng nào cho đúng?
Khi tắt strictNullChecks, null và undefined được coi là gán được vào mọi kiểu. Bật lên, chúng tách thành kiểu riêng, nên compiler bắt đầu báo những chỗ vốn đã có rủi ro runtime. Ba nhóm lỗi hay gặp: 1. Object is possibly 'null' —…
- Với một tập giá trị cố định (trạng thái đơn hàng, role), nên dùng `enum` hay union of string literal?
Trong code frontend hiện đại, union of string literal thường là lựa chọn mặc định; enum chỉ giữ khi cần một namespace giá trị thật ở runtime. Vì sao ưu tiên union: - Không sinh code runtime. enum (không phải const enum) biên dịch ra…
- `await res.json()` trả về kiểu gì? Viết `const user = await res.json() as User` có an toàn không?
res.json() trả về Promise<any, và as User không kiểm tra gì ở runtime — nó chỉ nói với compiler "cứ tin tôi". Nếu backend đổi field hoặc trả về lỗi, code vẫn biên dịch sạch rồi hỏng ở nơi khác, xa điểm gây lỗi. Ba…
- Bạn mô hình hoá state của một màn hình (loading / success / error) bằng type như thế nào?
Dùng discriminated union thay vì một object với nhiều field optional. Union có một field chung làm discriminant (thường là status), giúp compiler biết chính xác field nào tồn tại ở mỗi nhánh. Vì sao hơn cách { isLoading, data?, error? }: cách kia cho…
- Vì sao narrowing bị "mất" sau khi gọi một hàm khác hoặc bên trong callback? Khắc phục thế nào?
TypeScript narrow theo control flow analysis. Với property có thể thay đổi (mutable), compiler chỉ giữ kết quả narrow chừng nào nó còn chắc chắn không ai ghi đè. Gọi hàm khác hoặc vào một callback chạy sau là hai điểm nó buộc phải bỏ…
- Khai báo một object config: dùng `satisfies T`, `as T` và annotation `: T` khác nhau ra sao?
Ba cách kiểm tra ở ba mức khác nhau, và quan trọng nhất là chúng giữ lại lượng thông tin kiểu khác nhau. - : Palette (annotation) — kiểm tra đúng, nhưng biến bị mở rộng về đúng kiểu khai báo. a.green.toUpperCase() lỗi vì compiler…
- Vì sao truyền một biến chuỗi vào tham số kiểu union lại lỗi, thêm `as const` thì hết?
Vì literal widening. Khi khai báo bằng let hoặc đặt trong object literal, TypeScript mở rộng kiểu literal 'GET' thành string — do giá trị đó có thể bị gán lại. string không gán được vào union hẹp. Cách sửa: - as const cho object…
- Viết hàm `pick(obj, keys)` type-safe: vì sao cần `K extends keyof T`?
K extends keyof T là generic constraint — nó ràng buộc tham số kiểu K chỉ được là key thật của T, nhờ đó vừa chặn key sai lúc biên dịch, vừa để kiểu trả về mô tả đúng object con. Nếu bỏ constraint: -…
- Khi nào TypeScript suy luận generic thành `string` thay vì literal? Ép nó suy luận hẹp bằng cách nào?
TypeScript widen literal về string khi T không có constraint và không đứng riêng một mình ở kiểu trả về — ví dụ hàm trả { v } hay T[]. Trả về đúng T thì literal được giữ. Muốn giữ literal trong mọi trường hợp…
- Mapped type với key remapping (`as`) dùng làm gì? Ví dụ sinh type getter và đổi tên key.
Mapped type duyệt qua các key của một type để sinh type mới; mệnh đề as (TS 4.1) cho phép đổi tên key trong lúc duyệt — nhờ đó biến đổi được cả tên, không chỉ giá trị. Lọc key bằng cách remap về never…
- Dùng conditional type + `infer` để bóc kiểu bên trong (phần tử mảng, giá trị Promise) như thế nào? Distributive gây bẫy gì?
- Tự viết `DeepPartial<T>` và `RequireAtLeastOne<T>` như thế nào? Cần lưu ý gì khi đệ quy qua array, `Date`, function?
- Template literal type dùng để làm gì trong thực tế (route, event name)? Giới hạn của nó?
- Cần thêm field `user` vào `Request` của Express hoặc mở rộng session của thư viện auth — bạn khai báo ở đâu và bằng cú pháp gì?
- Vì sao gán thẳng object literal có field thừa thì lỗi, nhưng gán qua biến trung gian lại không?