Đang bổ sung câu trả lời tuyệt vời cho @fetzz.
CÂU TRẢ LỜI NGẮN
TLDR; Có hai nguyên nhân phổ biến cho loại thông báo lỗi này. Bạn đang làm việc đầu tiên (xem bên dưới). Cùng với văn bản, tôi giải thích rất chi tiết những gì thông báo lỗi này muốn truyền tải.
NGUYÊN NHÂN 1: Trong typscript, một cá thể cụ thể không được phép gán cho một tham số kiểu. Sau đây, bạn có thể xem ví dụ về 'vấn đề' và 'vấn đề đã được giải quyết', vì vậy bạn có thể so sánh sự khác biệt và xem những gì thay đổi:
VẤN ĐỀ
const func1 = <A extends string>(a: A = 'foo') => `hello!` // Error!
const func2 = <A extends string>(a: A) => {
//stuff
a = `foo` // Error!
//stuff
}
GIẢI PHÁP
const func1 = <A extends string>(a: A) => `hello!` // ok
const func2 = <A extends string>(a: A) => { //ok
//stuff
//stuff
}
Xem tại: Sân chơi TS
NGUYÊN NHÂN 2: Mặc dù bạn không gặp lỗi dưới đây trong mã của mình. Đây cũng là một trường hợp bình thường khi loại thông báo lỗi này xuất hiện. Bạn nên tránh làm điều này:
Lặp lại (do nhầm lẫn) Type Parametertrong một lớp, kiểu hoặc giao diện.
Đừng để sự phức tạp của đoạn mã dưới đây làm bạn bối rối, điều duy nhất tôi muốn bạn tập trung là cách loại bỏ ký tự 'A' giải quyết vấn đề:
VẤN ĐỀ:
type Foo<A> = {
map: <A,B>(f: (_: A) => B) => Foo<B>
}
const makeFoo = <A>(a: A): Foo<A> => ({
map: f => makeFoo(f(a)) //error!
})
GIẢI PHÁP:
type Foo<A> = {
map: <B>(f: (_: A) => B) => Foo<B>
}
const makeFoo = <A>(a: A): Foo<A> => ({
map: f => makeFoo(f(a))
})
Xem tại: Sân chơi TS
CÂU TRẢ LỜI DÀI
HIỂU THÔNG ĐIỆP LỖI
Sau đây, tôi sẽ phân tích từng phần tử của thông báo lỗi bên dưới:
Type '{}' is not assignable to type 'P'.
'{}' is assignable to the constraint of type 'P', but 'P' could be
instantiated with a different subtype of constraint'object'
LOẠI LÀ GÌ {}
Đó là một kiểu mà bạn có thể gán bất kỳ thứ gì ngoại trừ null hoặc undefined. Ví dụ:
type A = {}
const a0: A = undefined
const a1: A = null
const a2: A = 2
const a3: A = 'hello world'
const a4: A = { foo: 'bar' }
Xem tại: Sân chơi TS
NHỮNG GÌ LÀ is not assignable
Chỉ định là làm cho một biến của một kiểu cụ thể tương ứng với một cá thể cụ thể. Nếu bạn không khớp với loại phiên bản, bạn sẽ gặp lỗi. Ví dụ:
const a: number = 'hello world'
const b: number = 2
LÀ GÌ different subtype
Hai loại là bằng nhau : nếu chúng không thêm hoặc bớt các chi tiết liên quan đến nhau.
Hai loại khác nhau : nếu chúng không bằng nhau.
Loại Alà một loại phụ của loạiS : nếu Athêm chi tiết mà không xóa chi tiết đã tồn tại khỏi S.
kiểu Avà kiểu Blà các kiểu con khác nhau của kiểuS : Nếu Avà Blà kiểu con của S, nhưng Avà Blà các kiểu khác nhau. Nói cách khác: Avà Bthêm chi tiết vào loại S, nhưng chúng không thêm chi tiết giống nhau .
Ví dụ: Trong đoạn mã dưới đây, tất cả các câu sau đều đúng:
- A và D là loại bằng nhau
- B là kiểu con của A
- E không phải là kiểu con của A
- B và C là kiểu con khác nhau của A
type A = { readonly 0: '0'}
type B = { readonly 0: '0', readonly foo: 'foo'}
type C = { readonly 0: '0', readonly bar: 'bar'}
type D = { readonly 0: '0'}
type E = { readonly 1: '1', readonly bar: 'bar'}
type A = number
type B = 2
type C = 7
type D = number
type E = `hello world`
type A = boolean
type B = true
type C = false
type D = boolean
type E = number
LƯU Ý : Loại kết cấu
Khi bạn thấy trong TS việc sử dụng typetừ khóa, chẳng hạn như trong type A = { foo: 'Bar' }bạn nên đọc: Loại bí danh Alà trỏ đến cấu trúc loại{ foo: 'Bar' } .
Cú pháp chung là: type [type_alias_name] = [type_structure].
Hệ thống loại chỉ định chỉ kiểm tra chống lại [type_structure]và không chống lại [type_alias_name]. Điều đó có nghĩa là trong TS không có sự khác biệt về kiểu kiểm tra giữa sau: type A = { foo: 'bar }và type B = { foo: 'bar' }. Để biết thêm, hãy xem: Tài liệu chính thức .
constraint of type'X' LÀ GÌ
Giới hạn Loại đơn giản là những gì bạn đặt ở phía bên phải của từ khóa 'mở rộng'. Trong ví dụ dưới đây Type Constraintlà 'B'.
const func = <A extends B>(a: A) => `hello!`
Đọc: Loại Ràng buộc 'B' làconstraint of type 'A'
TẠI SAO LỖI XẢY RA
Tôi sẽ chỉ cho bạn ba trường hợp. Điều duy nhất sẽ thay đổi trong mỗi trường hợp là Type Constraint, không có gì khác sẽ thay đổi.
Điều tôi muốn bạn lưu ý là hạn chế Type Constraintáp đặt Type Parameter không bao gồm các loại phụ khác nhau . Hãy xem nó:
Được:
type Foo = { readonly 0: '0'}
type SubType = { readonly 0: '0', readonly a: 'a'}
type DiffSubType = { readonly 0: '0', readonly b: 'b'}
const foo: Foo = { 0: '0'}
const foo_SubType: SubType = { 0: '0', a: 'a' }
const foo_DiffSubType: DiffSubType = { 0: '0', b: 'b' }
TRƯỜNG HỢP 1: KHÔNG HẠN CHẾ
const func = <A>(a: A) => `hello!`
const c0 = func(undefined)
const c1 = func(null)
const c2 = func(() => undefined)
const c3 = func(10)
const c4 = func(`hi`)
const c5 = func({})
const c6 = func(foo)
const c7 = func(foo_SubType)
const c8 = func(foo_DiffSubType)
TRƯỜNG HỢP 2: MỘT SỐ HẠN CHẾ
Lưu ý dưới đây rằng hạn chế không ảnh hưởng đến các kiểu phụ.
RẤT QUAN TRỌNG : Trong Typecript Type Constraint không hạn chế các kiểu phụ khác nhau
const func = <A extends Foo>(a: A) => `hello!`
// call examples
const c0 = func(undefined) // error
const c1 = func(null) // error
const c2 = func(() => undefined) // error
const c3 = func(10) // error
const c4 = func(`hi`) // error
const c5 = func({}) // error
const c6 = func(foo) // ok
const c7 = func(foo_SubType) // ok <-- Allowed
const c8 = func(foo_DiffSubType) // ok <-- Allowed
TRƯỜNG HỢP 3: CÒN LẠI NHIỀU
const func = <A extends SubType>(a: A) => `hello!`
// call examples
const c0 = func(undefined) // error
const c1 = func(null) // error
const c2 = func(() => undefined) // error
const c3 = func(10) // error
const c4 = func(`hi`) // error
const c5 = func({}) // error
const c6 = func(foo) // error <-- Restricted now
const c7 = func(foo_SubType) // ok <-- Still allowed
const c8 = func(foo_DiffSubType) // error <-- NO MORE ALLOWED !
Xem trong sân chơi TS
PHẦN KẾT LUẬN
Chức năng bên dưới:
const func = <A extends Foo>(a: A = foo_SubType) => `hello!` //error!
Đưa ra thông báo lỗi này:
Type 'SubType' is not assignable to type 'A'.
'SubType' is assignable to the constraint of type 'A', but 'A'
could be instantiated with a different subtype of constraint
'Foo'.ts(2322)
Bởi vì Typecript suy ra Atừ lời gọi hàm, nhưng không có hạn chế trong ngôn ngữ hạn chế bạn gọi hàm với các kiểu con khác nhau của 'Foo'. Ví dụ: tất cả lệnh gọi của hàm dưới đây được coi là hợp lệ:
const c0 = func(foo)
const c1 = func(foo_SubType)
const c2 = func(foo_DiffSubType)
Do đó, việc gán một loại cụ thể cho một loại chung chung Type Parameterlà không chính xác vì trong TS, luônType Parameter có thể được khởi tạo thành một số kiểu phụ khác nhau tùy ý:
Giải pháp:
Đừng bao giờ gán một kiểu cụ thể cho một tham số kiểu chung chung, hãy coi nó là read-only! Thay vào đó, hãy làm điều này:
const func = <A extends Foo>(a: A) => `hello!` //ok!
Xem trong Sân chơi TS