😍Cách để khai báo 1 prop không được chấp nhận hoặc cảnh báo không tồn tại Full (ok)
https://medium.com/innovation-and-technology/deciphering-typescripts-react-errors-8704cc9ef402
Trước
components\Test.tsx
import React from 'react';
export default function components() {
return (
<div>
<CustomInput fieldName="colorField" />
</div>
)
}

Sau
components\Test.tsx
import React from 'react';
interface CustomInputProps {
fieldName: string;
}
class CustomInput extends React.Component<CustomInputProps> {
render() {
return <input name={this.props.fieldName} />
}
}
export default function components() {
return (
<div>
<CustomInput fieldName="colorField" />
</div>
)
}

Giải mã lỗi React của TypeScript
·
Theo
Đã xuất bản trongĐổi mới và Công nghệ·16 phút đọc·Ngày 28 tháng 6 năm 2018
2,2 nghìn
11
Kiểm tra kiểu tĩnh là một trong những biện pháp bảo vệ kỹ thuật yêu thích của tôi, đó là lý do tại sao tôi ưu tiên áp dụng trình kiểm tra kiểu khi chọn bộ công cụ phát triển ứng dụng web trong nhóm Kỹ thuật số của Thành phố Boston .
Kiểm tra kiểu tĩnh giảm rủi ro bảo trì phần mềm, vì nó chỉ ra những nơi bạn cần cập nhật mã để phù hợp với những thay đổi bạn đang thực hiện. Nó cũng tốt cho phát triển mới vì, với sự hỗ trợ của trình soạn thảo tốt, nó đảm bảo bạn đang gọi các hàm hiện có và cung cấp cho chúng các đối số mà chúng mong đợi.
Nhưng thứ sáu tuần trước, tôi nhận được tin nhắn trực tiếp từ đồng nghiệp John, người đã viết một số thành phần React:
Tôi ghét những lỗi đó, tôi định nói là không thích nhưng naaaaahhh tôi ghét chúng lol
John là một sinh viên mới tốt nghiệp trại huấn luyện, làm việc với tôi vào mùa hè với tư cách là một thành viên. Anh ấy cũng rất thoải mái, vì vậy việc nhìn thấy phản ứng mạnh mẽ này thực sự đánh thức tôi.
Tôi đã ném John vào thế giới kiểm tra kiểu mà không có sự chuẩn bị. Anh ấy đã trở thành nạn nhân của một nghịch lý về rào chắn : việc xử lý các thông báo lỗi "hữu ích" của trình kiểm tra có thể tốn nhiều công sức hơn là gỡ lỗi các vấn đề mà trình kiểm tra cảnh báo bạn.
Sự kết hợp của React, JSX và DOM tạo ra một số loại TypeScript phức tạp. Khi TypeScript phàn nàn, thông báo lỗi của nó rất dài dòng, với rất nhiều tên mà bạn không nhận ra từ mã của riêng bạn. Vì vậy, đối với John và tất cả những người mới làm quen với môi trường này, tôi xin giới thiệu hướng dẫn của mình để giải mã thông báo lỗi React / TypeScript của bạn.
(Bạn có thể nhận thấy rằng ứng dụng web Registry được viết bằng Flow . Đối với phần phát triển mới, chúng tôi đang làm việc bằng TypeScript .)
Tại sao lại phải kiểm tra kiểu React?
Hãy cùng xem chúng ta hy vọng đạt được điều gì khi sử dụng TypeScript với React ngay từ đầu. Khi mọi thứ diễn ra suôn sẻ, chúng ta sẽ bắt được những lỗi này:
Cố gắng truyền một prop mà một thành phần không muốn
Quên truyền một prop mà một thành phần yêu cầu
Nhận sai loại của một prop, chẳng hạn như truyền một chuỗi khi nó mong đợi một số
Nếu chúng ta viết những lỗi này, TypeScript sẽ hiển thị lỗi ngay trong trình soạn thảo của chúng ta. Nếu không có TypeScript, chúng ta sẽ phải phát hiện những lỗi này sau trong quá trình thử nghiệm và có thể sẽ rất tẻ nhạt khi phải gỡ lỗi để tìm ra lỗi xuất phát từ đâu.
(Có đáng để sử dụng công cụ để phát hiện những lỗi này hay không là câu hỏi dành cho nhóm của bạn. Tôi thấy nó rất hữu ích, đó là lý do chúng tôi ở đây.)
Lỗi với các phần tử DOM
Để bắt đầu, hãy xem xét việc sử dụng các phần tử DOM chuẩn trong JSX. TypeScript sẽ kiểm tra để đảm bảo rằng mọi thuộc tính bạn đặt vào thẻ HTML đều tồn tại và có đúng loại. Ví dụ:
render() {
trả về <kiểu đầu vào="văn bản" tên="màu" />;
}
Kiểu mã React/JSX ở trên kiểm tra tốt, vì <input>
s có cả thuộc tính type
và name
! Bạn sẽ không thấy bất kỳ lỗi nào. TypeScript có thể làm điều này vì có một thư viện React ( @types/react
) định nghĩa tất cả các phần tử HTML và các thuộc tính mà mỗi phần tử có.
Lưu ý: Trong hướng dẫn này, tôi sử dụng "thuộc tính" và "thuộc tính" thay thế cho nhau. "Thuộc tính" là tên gọi của chúng trong HTML, nhưng trên các thành phần React, chúng là "props". Và khi chúng nằm trên Đối tượng JavaScript, TypeScript gọi chúng là "thuộc tính".
Sử dụng một thuộc tính không tồn tại
Bây giờ chúng ta hãy viết sai chữ “ name
” và xem điều gì xảy ra:
render() {
trả về <kiểu đầu vào="văn bản" nmae ="màu" />;
}
Nếu trình soạn thảo của bạn hỗ trợ TypeScript, bạn sẽ thấy dòng đó có gạch chân màu đỏ và thông báo lỗi sau:

Có vẻ hơi khó khăn, nhưng chúng ta có thể phân tích từng phần một:
Property 'nmae'
— “Thuộc tính” là các thuộc tính trên<input>
thẻ. Vì vậy, lỗi này liên quan đến “nmae=”…"
”.does not exist on type
— Có một “kiểu”, một định nghĩa ở đâu đó về những gì được phép có trên<input>
, và “nmae
” không có trong danh sách.'DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>'
— OK, đây là một điều khó khăn. Điều này mô tả cách TypeScript nghĩ về<input>
các thuộc tính của ’. Tất cả các tên này (DetailedHTMLProps
,InputHTMLAttributes
, vàHTMLInputElement
) được định nghĩa trong thư viện React đó.DetailedHTMLProps
có nghĩa là các thuộc tính mà bất kỳ phần tử HTML nào cũng có thể có (nhưid
,tabIndex
, vàstyle
) vàInputHTMLAttributes
dành cho các thuộc tính cụ thể cho<input>
các phần tử (name
,value
, &c. ). Đây là bản mẫu mà bạn thường có thể bỏ qua, nhưngHTML***Element
phần này có thể là một manh mối hữu ích để giải mã điều này.
Bản sửa lỗi: Khi bạn thấy “ Property XXX does not exist on type
,” nghĩa là bạn đang thêm an XXX="…"
vào một phần tử không muốn có an XXX
trên đó. Mặc dù bản thân điều đó không phải là vấn đề—phần tử sẽ chỉ bỏ qua các thuộc tính mà nó không nhận ra—nhưng thường thì đó là dấu hiệu của lỗi. Trong trường hợp này, việc thêm a không phải là vấn đề nmae
, nhưng đó là vấn đề mà chúng ta nghĩ rằng mình đã thêm a name
nhưng thực tế lại không phải vậy.
Khi bạn thấy điều này, hãy kiểm tra lỗi đánh máy và kiểm tra tài liệu HTML để đảm bảo bạn có thuộc tính hoặc phần tử phù hợp với mục đích bạn đang cố gắng thực hiện.
Nhận sai loại thuộc tính
Có một lỗi khác có thể xảy ra với HTML: sử dụng sai kiểu cho một thuộc tính. Hãy thêm a size
vào <input>
và xem điều gì xảy ra:
render() {
trả về <kiểu đầu vào="văn bản" tên="màu" kích thước="6" />;
}
Đây chính xác là cách bạn viết trong trang HTML, nhưng TypeScript lại hiển thị lỗi:

Types of property 'size' are incompatible.
— Chúng ta đang nói vềsize
hiện tại. Lưu ý cách nó nói "types" ở dạng số nhiều. Đó là vì tất cả các lỗi kiểu đều là sự không nhất quán . Lỗi này nằm giữa hai kiểu: một kiểu từ mã của chúng ta và một kiểu từ<input>
định nghĩa của React (hãy nhớ lạiDetailedHTMLProps<…>
phần chúng ta đã thấy trong lỗi trước).Type 'string'
— Đây là kiểu đầu tiên, kiểu cho đối số mà chúng ta đã viết,"6"
là một chuỗi, vì tất cả các thuộc tính JSX được trích dẫn đều là chuỗi.is not assignable to
— Đây là cách diễn đạt tinh tế của từ “không phải”. Nó làm rõ điều “không tương thích” giữa hai loại.type 'number | undefined'
— Đây là kiểu thứ hai trong hai kiểu, kiểu mà thư viện React cho là phù hợp với thuộc tính<input>
'ssize
. The|
được gọi là toán tử “union”, nhưng bạn có thể đọc là “or”: “size
phải là một số hoặc không xác định”.
Sửa lỗi: Chúng ta cần thay đổi một trong hai kiểu để làm cho chúng nhất quán. Vì chúng ta không thể thay đổi thư viện React để chấp nhận một chuỗi, chúng ta phải thay đổi mã của mình để truyền một số:
render() {
<input type="text" name="color" size={6} />
}
Hãy nhớ rằng đó {}
là cách tạo biểu thức JavaScript trong JSX. Bây giờ thay vì chuỗi, chúng ta cung cấp số và lỗi TypeScript sẽ biến mất.
Thông báo lỗi cho biết kiểu từ thư viện React là 'number | undefined'
. “Undefined” giống như việc bỏ nó đi, đó là lý do tại sao các ví dụ trước của chúng tôi đã kiểm tra kiểu mà không có size
. Nhưng điều này giải thích tại sao thông báo lỗi cho biết “is not assigned to” thay vì “isn't.” 6
là một số, không phải là “number or undefined.” Nhưng, một số có thể gán cho “number or undefined,” vì “or.”
Thư viện kiểu React không yêu cầu bất kỳ thuộc tính nào trên các thành phần HTML, do đó không có lỗi "quên truyền prop mà một thành phần yêu cầu" trong phần này. Lỗi này sẽ xuất hiện khi chúng ta xử lý các thành phần tùy chỉnh.
Tất cả các lỗi kiểu đều là sự không nhất quán
Tôi đã đề cập đến điều này ở trên trong phần phân tích size
lỗi, nhưng đây là một khái niệm quan trọng đến mức tôi muốn nhắc lại:
Tất cả các lỗi kiểu đều là sự không nhất quán .
Ý tôi là những dòng chữ TypeScript màu đỏ đó ở đó vì một phần trong mã của bạn không phù hợp với phần khác. Phần nào đúng? Công việc của bạn là tìm ra điều đó bằng cách suy nghĩ về những gì bạn đang cố gắng làm cho mã của mình thực hiện.
Một trong những lý do khiến lỗi kiểu có thể gây nhầm lẫn khi diễn giải là TypeScript sẽ chỉ gạch chân một trong những nơi xảy ra sự không nhất quán. Ví dụ đầu tiên bên dưới là lỗi khi TypeScript gọi ra một cái gì đó trong JSX, nhưng phần đó thực sự đúng và chúng ta quyết định định nghĩa kiểu là sai.
Lỗi với các thành phần React tùy chỉnh
Nguyên tắc kiểm tra kiểu của các thành phần tùy chỉnh về cơ bản giống với các phần tử DOM, nhưng tên của các kiểu lại khó hiểu hơn.
Đối với phần này, chúng tôi sẽ sử dụng thành phần mẫu sau:
lớp CustomInput mở rộng React.Component {
render() {
return <input />;
}
}
Sử dụng đạo cụ của riêng bạn
Giả sử chúng ta sử dụng this để xây dựng một form, vì vậy chúng ta cần truyền vào một name
phương thức có thể đi vào đó <input>
. Trong React, điều đó có nghĩa là thêm một prop. Đây là render
phương thức mới:
render() {
trả về < tên đầu vào={this.props.fieldName} />
}
Có thể được sử dụng bởi một thành phần khác như thế này:
render() {
trả về (
<form>
<CustomInput fieldName="colorField" />
</form>
);
}
Có vẻ đơn giản, và trong JavaScript thông thường trường hợp này hoàn toàn có thể hoạt động, không có lỗi. Nhưng TypeScript đã tìm thấy điều gì đó để phàn nàn:

Property 'fieldName'
— Chúng ta đã thấy ngôn ngữ này trước đây với thuộc tính<input>
'snmae
, nhưng bây giờ nó đề cập đến một “thuộc tính” trênthis.props
đối tượng, thay vì một thuộc tính trên thẻ HTML.does not exist on type
— Đây cũng là cùng một ngôn ngữ. TypeScript có ý kiến về những thuộc tính nào là và không phải là trênthis.props
, vàfieldName
nằm trong đống “không”.'Readonly<{ children?: ReactNode; }> & Readonly<{}>'
— Được rồi, điều này khó đọc. Đây là kiểu mà TypeScript nghĩ đến khi chúng ta nóithis.props
.
Phần cuối cùng cần được giải thích chi tiết hơn:
s
Readonly
có nghĩa là bạn không thể thay đổithis.props
. Bạn không nên làm điều đó với React, vì vậy TypeScript thực thi điều đó.{ children?: ReactNode; }
có ở đó không vì tất cả các thành phần React đều có thể cóthis.props.children
giá trị.ReactNode
là bất kỳ thứ gì mà React biết cách hiển thị: chuỗi, thành phần, v.v. Điều đó?
có nghĩa là thuộc tính này là tùy chọn—bạn không cần phải truyền các thành phần con choCustomInput
.&
trong TypeScript tạo ra một "giao điểm" giữa hai kiểu, giống như một đối tượng có tất cả các thuộc tính từ mỗi kiểu được hợp nhất với nhau. Vì vậy,this.props
có một kiểu được tạo thành từ tất cả các thuộc tính của{ children?: ReactNode; }
kết hợp với tất cả các thuộc tính của{}
. Mà không có bất kỳ thuộc tính nào.
Điều này có nghĩa là this.props
có một children
thuộc tính tùy chọn nhưng không có fieldName
thuộc tính nào.
Cách khắc phục: Để khắc phục điều này, chúng ta thực sự phải đưa ra lựa chọn. Hãy nói cùng tôi ngay bây giờ:
Tất cả các lỗi kiểu đều là sự không nhất quán .
Có hai điều không đồng ý. Trong render
phương pháp của bạn, bạn đang cố gắng sử dụng this.props.fieldName
. Nhưng khi bạn khai báo thành phần của mình, bạn đã không cung cấp cho nó một fieldName
prop. Cái nào đúng? render
Phương pháp hay khai báo thành phần?
Với các phần tử DOM, chúng ta biết rằng các thuộc tính mong đợi là chính xác vì chúng đến từ một thư viện mà chúng ta tin tưởng. Nhưng đây là mã của riêng chúng ta, vì vậy chúng ta phải chọn những gì cần thay đổi để lỗi biến mất. Điều đó có nghĩa là ngừng cố gắng sử dụng this.props.fieldName
, hoặc thêm fieldName
vào khai báo thành phần của chúng ta.
Theo mặc định, tất cả React.Component
s đều có this.props
kiểu {}
, mà chúng ta thấy trong &
câu lệnh trong lỗi. Vì chúng ta thực sự muốn có một fieldName
prop, chúng ta phải thêm nó:
giao diện CustomInputProps {
fieldName: string;
}lớp CustomInput mở rộng React.Component <CustomInputProps> {
render() {
trả về <input name={this.props.fieldName} />;
}
}
Chuyện gì đang xảy ra ở đây? Chúng ta bắt đầu với interface
, đó là cách chúng ta tạo một "kiểu đối tượng" mới trong TypeScript. Chúng ta đang nói rằng bất kỳ đối tượng nào có kiểu CustomInputProps
phải là "một đối tượng có thuộc fieldName
tính, phải là một chuỗi".
Ngoài ra: Tại sao chúng ta lại nói về các loại đối tượng?
CustomInputProps
là một kiểu đối tượng, có nghĩa là nó mô tả “hình dạng” của một đối tượng JavaScript. Ví dụ:
const obj: CustomInputProps = {
fieldName: 'myInput',
};
Đó là một const
lệnh được gọi obj
và : CustomInputProps
cho TypeScript biết rằng giá trị của nó cần phải khớp với CustomInputProps
hình dạng. Chúng tôi khởi tạo nó bằng một đối tượng theo nghĩa đen có fieldName
thuộc tính cần thiết, do đó nó kiểm tra kiểu!
Chúng ta hãy bỏ qua fieldName
phần bất động sản và xem điều gì xảy ra:
const obj: CustomInputProps = {} ;
{}
không khớp CustomInputProps
, vì vậy đây là cách TypeScript phàn nàn:

Type '{}'
— Đây là TypeScript mô tả kiểu giá trị mà chúng ta đang cố gắng gán choobj
: một đối tượng không có trường nào.is not assignable to
— Người bạn cũ của chúng ta “không thể gán cho”. Chúng ta đang cố gắng thực hiện một phép gán: gán cho{}
,obj
nhưng TypeScript lại nói rằng chúng ta không thể làm điều đó.type 'CustomInputProps'.
— Đây là vì nó là thứ chúng ta đã tuyên bốobj
. Do đó, nó là kiểu được gán cho .Property 'fieldName' is missing in type '{}'.
— Bây giờ TypeScript đang nêu rõ lý do tại sao một đối tượng có kiểu{}
không thể gán cho thứ gì đó có kiểuCustomInputProps
: Không cófieldName
, và, theointerface
khai báo ở trên, tất cảCustomInputProps
các đối tượng phải cófieldName
.
Bây giờ chúng ta hãy xem điều gì xảy ra khi chúng ta đưa trở lại fieldName
, nhưng cũng thêm một trường không phải là một phần của CustomInputProps
kiểu:
const obj: CustomInputProps = {
fieldName: 'myInput',
placeholder: 'Nhập nội dung gì đó vào đây',
};
Điều đó không được phép:

Type '{ fieldName: string; placeholder: string; }'
— Đây là kiểu mới của đối tượng theo nghĩa đen của chúng ta. Hãy xem cách nó cóplaceholder
thuộc tính này.is not assignable to type 'CustomInputProps'.
— Giống như trước. TypeScript cho rằng lệnh gán này là bất hợp pháp.Object literal may only specify known properties, and 'placeholder' does not exist in type 'CustomInputProps'.
— Đây là lời giải thích cho lý do tại sao trường hợp này “không thể gán được.”CustomInputProps
không cóplaceholder
thuộc tính được khai báo tronginterface
khối của nó.
Đây là trường hợp tương tự như khi chúng ta thêm nmae
. <input>
Việc thêm thuộc tính bổ sung placeholder
không phải là lỗi, vì mã đang chạy CustomInputProps
sẽ bỏ qua nó, nhưng đó là dấu hiệu cho thấy có thể có lỗi.
Quay lại lý do tại sao chúng ta lại nói về các kiểu đối tượng ngay từ đầu. Chúng liên quan gì đến React props? Đối tượng có {}
dấu ngoặc nhọn ngoằn ngoèo, không phải <>
dấu ngoặc nhọn của JSX. Để giải thích điều này, hãy quay lại ví dụ về phần tử DOM của chúng ta và nói một chút về JSX.
<input name="color" size={6} />
Trình duyệt không thể tự hiểu JSX này, chúng chỉ hiểu JavaScript thuần túy. Chúng tôi thường sử dụng trình biên dịch TypeScript hoặc một công cụ như Babel để lấy JSX và tạo JavaScript từ đó. Sau đây là đoạn mã trông như thế nào dưới dạng JavaScript:
React.createElement('đầu vào', {
tên: 'màu',
kích thước: 6,
});
Này, những thứ đó name="color"
và size={6}
các thuộc tính bây giờ là một đối tượng theo nghĩa đen! Đối số đầu tiên createElement
là những gì chúng ta đang tạo ra—một lớp cho các thành phần tùy chỉnh, một tên thẻ cho các phần tử HTML—và đối số thứ hai là các props để truyền vào nó.
Đây là lý do tại sao TypeScript luôn nói về props như các kiểu đối tượng. Khi kiểm tra kiểu mã React, nó đảm bảo rằng đối số thứ hai createElement
có kiểu khớp với (“có thể gán cho”) kiểu đã khai báo của props của thành phần.
(Vì nó chỉ chuyển đổi mọi thứ thành JavaScript thuần túy, nên JSX đôi khi được gọi là "cú pháp ngọt ngào". Thực ra, nó không cần thiết—chúng ta có thể createElement
tự viết những câu lệnh đó—nhưng nó làm cho mã trở nên ngọt ngào hơn.)
Bây giờ quay lại khai báo kiểu props
Hãy cùng nhớ lại chúng ta đã ở đâu:
giao diện CustomInputProps {
fieldName: string;
}lớp CustomInput mở rộng React.Component <CustomInputProps> {
render() {
trả về <input name={this.props.fieldName} />;
}
}
Bây giờ chúng ta đã khai báo the interface
we want—“hình dạng” của props của thành phần—chúng ta thực sự cần phải bảo TypeScript sử dụng nó cho CustomInput
. Đó là nơi the React.Component<CustomInputProps>
xuất hiện. Các <…>
bit cho phép chúng ta truyền tham số kiểu . Hãy nghĩ về nó như một cách để điều chỉnh React.Component
, giống như cách bạn sử dụng (…)
s để truyền đối số cho các hàm. ReactComponent
sử dụng tham số kiểu đầu tiên của nó làm kiểu for this.props
, thay thế mặc định {}
.
Chúng ta có thể quay lại render
phương pháp của mình và xem this.props
hiện tại là gì. Trong Visual Studio Code, bạn có thể di chuột qua nó:

React.Component<CustomInputProps, {}, any>
— Đây là Visual Studio cho chúng ta biết điều gìthis
. Nó gần giống vớiextends React.Component<CustomInputProps>
khai báo lớp của chúng ta, chỉ với các giá trị mặc định choCustomInputProps
2 tham số kiểu bổ sung được viết rõ ràng..props:
— Bởi vì đó chính là thứ chúng ta đang quan tâm.Readonly<{ children?: React.ReactNode; }> & Readonly<CustomInputProps>
— Bạn còn nhớReadonly
thứ này từ trước không? Bây giờ thì nóCustomInputProps
thay thế cho{}
.
Tuyệt! Với thay đổi này, this.props
vẫn giữ nguyên thuộc tính trước đó children
nhưng giờ cũng có mọi thứ từ CustomInputProps
, đặc biệt là fieldName
thuộc tính.
Ngoài ra còn có trạng thái
Sử dụng this.state
gần giống với this.props
, vì vậy tôi sẽ không đi sâu vào nó. Các lỗi bạn nhận được từ nó về cơ bản sẽ giống nhau. Để cung cấp cho trạng thái của thành phần một loại, hãy sử dụng tham số loại thứ hai cho React.Component
, như thế này:
giao diện Props {
fieldName: string;
}giao diện State {
lỗi: chuỗi | null;
}lớp CustomInput mở rộng React.Component<Props, State > {
state = {
lỗi: null;
};
}
Ví dụ trên cũng cho thấy việc khởi tạo state
với giá trị mặc định. Bạn cũng có thể thực hiện việc này this.state = {…}
trong constructor()
phương thức. Tôi cũng đã rút ngắn tên giao diện thành “ Props
” và “ State
” để chúng không bị bao bọc. Chúng thực sự có thể là bất kỳ thứ gì, miễn là bạn nhất quán giữa interface
và React.Component<…>
.
Các props cần thiết trên một thành phần tùy chỉnh
Hãy quay lại sử dụng CustomInput
thành phần của chúng ta. Điều này sẽ tương tự như khi chúng ta tạo <input>
các phần tử.
Hãy nhớ lại chỗ chúng ta dừng lại CustomInput
:
giao diện CustomInputProps {
fieldName: string;
}lớp CustomInput mở rộng React.Component<CustomInputProps> {
…
}
Chúng ta hãy cùng làm một cái nhé!
render() {
trả về (
<form>
<CustomInput />
</form>
);
}
Và lỗi là…

Mọi chuyện ngày càng trở nên phức tạp hơn, phải không?
Type '{}'
— Để giải thích điều này, hãy nhớ cách JSX hoạt động. Dòng mã trên của chúng ta chuyển thànhReact.createElement(CustomInput, {})
.{}
vì chúng ta không viết bất kỳ props nào trong JSX.Type '{}'
TypeScript đang mô tả đối số props thứ hai đó.is not assignable to
— Vẫn là cách cũ. Có sự không nhất quán trong các loại!'IntrinsicAttributes & IntrinsicClassAttributes<CustomInput> & Readonly<{ children?: ReactNode; }>...'
— Đây là một mớ hỗn độn đến mức TypeScript thực sự từ bỏ và dừng lại trước khi đến cuối. Các bit "nội tại" bao gồm các đạo cụ React phổ biến nhưkey
vàref
. Bạn có thể thấyReadonly<{ children?: ReactNode; }>
ở cuối, đó là phần bắt đầu củathis.props
kiểu mà chúng ta đã thấy trước đó. Kiểu hoàn chỉnh ở đây là:IntrinsicAttributes & IntrinsicClassAttributes<CustomInput> & Readonly<{ children?: ReactNode; }> & Readonly<CustomInputProps>
, nhưng thành thật mà nói, bạn có thể bỏ qua dòng này.Type '{}' is not assignable to type 'Readonly<CustomInputProps>'
— Ở đây TypeScript gọi ra phần nào củaIntrinsicAttributes & … & …
nó đang gặp sự cố.{}
có thể gán hoàn hảo choIntrinsicAttributes
,IntrinsicClassAttributes
, vàReadonly<{ children?: ReactNode; }>
vì tất cả các trường của chúng đều là tùy chọn. Phần không thể gán được làCustomInputProps
.Property 'fieldName' is missing in type '{}'.
— Đây là phần hữu ích nhất của thông báo lỗi. Nótype '{}'
gọi lạicreateElement
đối số thứ hai, loại props từ JSX.
Sửa lỗi: Một lần nữa, lỗi kiểu là đánh dấu sự không nhất quán trong mã. Như đã viết, CustomInput
muốn có một fieldName
prop, nhưng bạn không cung cấp cho nó. Vì vậy, hãy cung cấp cho nó một prop, hoặc làm cho nó không muốn có prop ngay từ đầu. Hãy xem cách chúng ta sẽ thực hiện từng cái.
Để vượt qua fieldName
, chúng ta làm như sau:
<CustomInput fieldName="myField" />
Sau khi dịch JSX, nó trở thành:
React.createElement(CustomInput, { fieldName: "myField" } );
Kiểu của đối số props thứ hai là { fieldName: string }
có thể gán cho CustomInputProps
.
Đây là trường hợp khác, làm cho fieldName
tùy chọn. Đối với trường hợp này, chúng ta cần thay đổi where interface
đã CustomInputProps
được khai báo.
giao diện CustomInputProps {
fieldName? : string;
}
Bạn thấy đấy, có một ?
there ở đây không? Điều đó cho TypeScript biết rằng thuộc tính này là tùy chọn. Bây giờ cả hai { fieldName: string }
và {}
đều có thể gán cho CustomInputProps
.
Điều này có nghĩa là this.props.fieldName
bây giờ có kiểu 'string | undefined'
, vì vậy TypeScript sẽ khiến bạn tính đến điều đó trong phần còn lại của mã. Không gọi this.props.fieldName.length
mà không kiểm tra xem nó đã được định nghĩa trước chưa!
Truyền đạo cụ không xác định
Cuối cùng, hãy xem các thông báo lỗi bạn nhận được khi bạn cung cấp một prop cho một thành phần tùy chỉnh không nằm trong loại props của nó. TypeScript có hai thông báo lỗi khác nhau, tùy thuộc vào các props khác mà bạn truyền.
<CustomInput fieldName="myField" placeholder="Nhập ở đây" />

Thông báo lỗi này giống với thông báo chúng ta nhận được nmae
trong ví dụ đầu, chỉ có CustomInput
kiểu props dài hơn ' ở cuối. Thật không may là thông báo này bị cắt trước khi nó nói CustomInputProps
, vì đó là một phần thông tin thực sự giúp theo dõi những gì đang diễn ra. Chỉ cần nhớ rằng khi bạn thấy thông báo này, rất có thể prop bạn đang truyền không được định nghĩa trong giao diện props của chính thành phần.
Thật kỳ lạ, nếu chúng ta bỏ đi fieldName
thì thông báo lỗi sẽ khác:
giao diện xuất khẩu CustomInputProps {
fieldName?: string;
}<CustomInput placeholder="Nhập ở đây" />;

Chúng ta có thể thấy { placeholder: string; }
kiểu từ createElement
câu lệnh ẩn sau hậu trường và IntrinsicAttributes & …
kiểu cho CustomInput
props của 's. Chỉ là vì một lý do nào đó mà tôi không biết TypeScript nói "không có thuộc tính chung" thay vì "không tồn tại".
Cách khắc phục: Giải quyết sự không nhất quán! Thêm placeholder
vào CustomInputProps
hoặc xóa nó khỏi <CustomInput … />
.
Phù!
Đây rồi. Giải thích về các lỗi TypeScript phổ biến nhất mà bạn gặp phải trong React JSX và cách bạn có thể giải quyết chúng. Hy vọng điều đó sẽ làm giảm bớt sự tức giận trong tương lai khi lập trình.
Tôi thừa nhận rằng việc tìm ra những cách mới để kiểm tra kiểu để bắt lỗi là một trong những bài tập lập trình yêu thích của tôi. Trong cơ sở mã Boards and Commissions mới , chúng tôi đang sử dụng ts2gql
để biến giao diện TypeScript thành lược đồ GraphQL, nghĩa là chúng tôi có thể sử dụng các giao diện TypeScript đó để kiểm tra kiểu rất chính xác cho trình phân giải của mình . Cũng giống như với ứng dụng web Registry, chúng tôi đang sử dụng apollo-codegen
để tạo đối số và kiểu đầu ra cho các truy vấn GraphQL và chúng tôi cũng đã thêm vào sql-ts
để tạo kiểu TypeScript từ các bảng SQL Server.
Đây là lời nhắc nhở hữu ích đối với tôi và bất kỳ ai đang lắp ráp dụng cụ, rằng lan can bảo vệ chỉ hiệu quả khi bạn biết nó đang bảo vệ cái gì.
Lời cảm ơn
Guillaume Marceau , khi còn là sinh viên sau đại học, đã giúp tôi hiểu cách lỗi kiểu phát sinh từ hai phần xung đột của một chương trình. James Duffy đã hiệu đính bài viết này.
Và tất nhiên là cảm ơn John vì đã vượt qua tất cả những điều này một cách mạnh mẽ.
Deciphering TypeScript’s React errors
·
Follow
Published inInnovation and Technology·16 min read·Jun 28, 2018
2.2K
11
Static type checking is one of my favorite engineering guard rails, which is why I made adopting a typechecker a priority when choosing the toolset for webapp development on the City of Boston’s Digital team.
Static type checking de-risks software maintenance, since it reveals places where you need to update code to accommodate changes you’re making. It’s equally good for new development since, with good editor support, it ensures you’re calling functions that exist and are giving them the arguments they expect.
But, last Friday, I got a DM from my co-worker John, who has been writing some React components:
I hate those errors, I was going to say dislike but naaaaahhh I hate them lol
John’s a recent bootcamp grad, working with me for the summer as a fellow. He’s also super-chill, so seeing this strong reaction really woke me up.
I had thrown John into a type-checking world without preparation. He fell victim to a paradox of guard rails: it can take more effort to deal with a checker’s “helpful” error messages than it would ever be to debug the problems it’s warning you against.
The combination of React, JSX, and the DOM make for some hairy TypeScript types. When TypeScript complains, its error messages are verbose, with a lot of names you don’t recognize from your own code. So, for John and everyone else new to this environment, I present my guide to decoding your React / TypeScript error messages.
(You might notice that the Registry webapp was written with Flow. For new development we’re working in TypeScript.)
Why even typecheck React?
Let’s see what we hope to get out of using TypeScript with React in the first place. When things go smoothly, we’ll be catching these bugs:
Trying to pass a prop that a component doesn’t want
Forgetting to pass a prop that a component requires
Getting a prop’s type wrong, such as passing a string when it expects a number
If we write these bugs, TypeScript will show an error in our editor right away. Without TypeScript, we’d have to catch these bugs later during testing, and it might be tedious debugging to figure out where they come from.
(Whether or not it’s worth it to use a tool to catch these bugs is a question for your team. I find it valuable, which is why we’re here.)
Errors with DOM elements
For starters, let’s look at using standard DOM elements in JSX. TypeScript will check to make sure that every attribute you put on an HTML tag exists and is of the right type. For example:
render() {
return <input type="text" name="color" />;
}
The above React/JSX code type checks fine, because <input>
s have both type
and name
attributes! You won’t see any errors. TypeScript can do this because there’s a React library (@types/react
) that defines all HTML elements and what attributes they each take.
Note: In this guide I use “attribute” and “property” pretty much interchangeably. “Attribute” is what they’re called in HTML, but on React components they’re “props.” And, when they’re on a JavaScript Object, TypeScript calls them “properties.”
Using a property that doesn’t exist
Now let’s mis-spell “name
” and see what happens:
render() {
return <input type="text" nmae="color" />;
}
If you have TypeScript support in your editor, you should get a red underline on that line, and the following error message:

That looks a little daunting, but we can break it down piece-by-piece:
Property 'nmae'
— The “properties” are the attributes on the<input>
tag. So this error is about “nmae=”…"
”.does not exist on type
— There’s a “type,” a definition somewhere of what is allowed to be on<input>
, and “nmae
” isn’t on the list.'DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>'
— OK, this is a doozy. This describes how TypeScript thinks of<input>
’s attributes. All of these names (DetailedHTMLProps
,InputHTMLAttributes
, andHTMLInputElement
) are defined in that React library.DetailedHTMLProps
means attributes that any HTML element can have (likeid
,tabIndex
, andstyle
) andInputHTMLAttributes
are for ones specific to<input>
elements (name
,value
, &c.). This is boilerplate you can typically gloss over, but theHTML***Element
part can be a useful clue in deciphering this.
The fix: When you see “Property XXX does not exist on type
,” it means you’re adding an XXX="…"
to an element that doesn’t want an XXX
on it. While that is not itself a problem—the element would just ignore attributes it doesn’t recognize—it’s usually a sign of a bug. In this case, it’s not a problem to add a nmae
, but it is a problem that we thought we were adding a name
but didn’t actually.
When you see this, check for typos, and check the HTML docs to make sure you’ve got the attribute or element right for what you’re trying to do.
Getting a property’s type wrong
There’s another error that can come up with HTML: using the wrong type for an attribute. Let’s add a size
to the <input>
and see what happens:
render() {
return <input type="text" name="color" size="6" />;
}
This is exactly how you’d write it in an HTML page, but TypeScript shows an error:

Types of property 'size' are incompatible.
— We’re talking aboutsize
now. Note how it says “types” with a plural. That’s because all type errors are inconsistencies. This error is between two types: the one from our code, and the one from React’s<input>
definition (remember theDetailedHTMLProps<…>
bit we saw in the last error).Type 'string'
— This is the first of the types, the one for the argument that we wrote."6"
is a string, because all quoted JSX attributes are strings.is not assignable to
— This is a nuanced way of saying “isn’t.” It’s clarifying what is “incompatible” about the two types.type 'number | undefined'
— This is the second of the two types, the one that the React library said is right for<input>
’ssize
attribute. The|
is known as a “union” operator, but you can read it as “or”: “size
must be a number or undefined.”
The fix: We need to change one or the other of the types to make them consistent. Since we can’t change the React library to accept a string, we have to change our code to pass a number:
render() {
<input type="text" name="color" size={6} />
}
Remember that {}
is the way to make a JavaScript expression in JSX. Now instead of a string, we’re providing a number, and the TypeScript error goes away.
The error message said that the type from the React library was 'number | undefined'
. “Undefined” is the same as leaving it off, which is why our previous examples typechecked without a size
. But this explains why the error message said “is not assignable to” instead of “isn’t.” 6
is a number, not a “number or undefined.” But, a number is assignable to a “number or undefined,” because of the “or.”
The React type library doesn’t require any attributes on HTML elements, so there’s no “forgetting to pass a prop that a component requires” error in this section. That will come up when we deal with custom components.
All type errors are inconsistencies
I mentioned this above in the breakdown of the size
bug, but it’s an important enough concept that I want to call it out:
All type errors are inconsistencies.
What I mean by this is those red TypeScript squiggles are there because one part of your code doesn’t agree with another part. Which part is right? Your job is to figure that out by thinking about what you’re trying to make your code do.
One of the reasons that type errors can be confusing to interpret is that TypeScript will only underline one of the places where the inconsistency is happening. The first example below is an error where TypeScript calls out something in the JSX, but that part is actually right and it’s the type definition that we decide is wrong.
Errors with custom React components
The principles of typechecking custom components are basically the same as DOM elements, but the names of the types get more confusing.
For this section, we’ll use the following sample component:
class CustomInput extends React.Component {
render() {
return <input />;
}
}
Using your own props
Say we’re using this to build a form, so we need to pass in a name
that can go on that <input>
. In React, that means adding a prop. Here’s the new render
method:
render() {
return <input name={this.props.fieldName} />
}
Which might get used by another component like this:
render() {
return (
<form>
<CustomInput fieldName="colorField" />
</form>
);
}
Seems straightforward, and in plain JavaScript this case would totally work, no bugs. But TypeScript has found something to complain about:

Property 'fieldName'
— We saw this language before with the<input>
’snmae
attribute, but now it’s referring to a “property” on thethis.props
object, rather than one on an HTML tag.does not exist on type
— This is also the same language. TypeScript has an opinion about what properties are and are not onthis.props
, andfieldName
is in the “not” pile.'Readonly<{ children?: ReactNode; }> & Readonly<{}>'
— OK, this is hard to read. This is the type that TypeScript thinks of when we saythis.props
.
That last bit needs a more detailed explanation:
The
Readonly
s mean that you can’t changethis.props
. You shouldn’t be doing that with React, so TypeScript enforces it.{ children?: ReactNode; }
is there because all React components can have athis.props.children
value.ReactNode
is anything that React knows how to render: strings, components, and so on. The?
means that this property is optional—you don’t need to pass children toCustomInput
.&
in TypeScript makes an “intersection” between two types, which is kind of like an object that has all the properties from each of them merged together. So,this.props
has a type that’s made up of all the properties of{ children?: ReactNode; }
combined with all the properties of{}
. Which doesn’t have any.
That comes together to mean that this.props
has an optional children
property, but no fieldName
property.
The fix: To fix this, we actually have to make a choice. Say it with me now:
All type errors are inconsistencies.
Two things don’t agree. In your render
method you’re trying to use this.props.fieldName
. But when you declared your component, you didn’t give it a fieldName
prop. Which is right? The render
method or the component declaration?
With DOM elements, we knew that the expected attributes were correct because they came from a library we trust. But this is our own code, so it’s up to us to pick what to change to make the error go away. That means either stop trying to use this.props.fieldName
, or add fieldName
to our component’s declaration.
By default, all React.Component
s have a this.props
type of {}
, which we saw in the &
statement in the error. Since we really do want to have a fieldName
prop, we have to add it:
interface CustomInputProps {
fieldName: string;
}class CustomInput extends React.Component<CustomInputProps> {
render() {
return <input name={this.props.fieldName} />;
}
}
What’s going on here? We start with interface
, which is how we make a new “object type” in TypeScript. We’re saying that any object of type CustomInputProps
must be “an object with a fieldName
property, which must be a string.”
Aside: Why are we talking about object types?
CustomInputProps
is an object type, which means that it describes the “shape” of a JavaScript object. For example:
const obj: CustomInputProps = {
fieldName: 'myInput',
};
That’s a const
called obj
, and : CustomInputProps
tells TypeScript that its value needs to match the CustomInputProps
shape. We initialize it with an object literal that has the necessary fieldName
property, so it typechecks!
Let’s leave off the fieldName
property and see what happens:
const obj: CustomInputProps = {};
{}
doesn’t match CustomInputProps
, so here’s how TypeScript complains:

Type '{}'
— This is TypeScript describing the type of the value that we’re trying to assign toobj
: an object with no fields.is not assignable to
— Our old friend “is not assignable to.” We’re trying to make an assignment: assigning{}
toobj
, but TypeScript is saying we can’t do it.type 'CustomInputProps'.
— This is here because it’s what we declaredobj
to be. Therefore it’s the type that’s being assigned to.Property 'fieldName' is missing in type '{}'.
— Now TypeScript is being specific about why an object of type{}
is not assignable to something of typeCustomInputProps
: There’s nofieldName
, and, because of theinterface
declaration from above, allCustomInputProps
objects must have afieldName
.
Now let’s see what happens when we put back fieldName
, but also add a field that’s not part of the CustomInputProps
type:
const obj: CustomInputProps = {
fieldName: 'myInput',
placeholder: 'Type something here',
};
That’s not allowed:

Type '{ fieldName: string; placeholder: string; }'
— This is the new type of our object literal. See how it now has theplaceholder
property.is not assignable to type 'CustomInputProps'.
— Same as before. TypeScript thinks this assignment is illegal.Object literal may only specify known properties, and 'placeholder' does not exist in type 'CustomInputProps'.
— This is the explanation for why this case is “not assignable.”CustomInputProps
doesn’t have aplaceholder
property declared in itsinterface
block.
This is a similar case to when we put nmae
on an <input>
. Adding the extra placeholder
property is not in itself a bug, since code working on CustomInputProps
would ignore it, but it’s a sign that there’s probably a bug.
Back to why we’re even talking about object types in the first place. What do they have to do with React props? Objects have {}
squiggly braces, not the <>
angle brackets of JSX. To explain this, let’s go back to our DOM element example and talk a bit about JSX.
<input name="color" size={6} />
Browsers can’t understand this JSX on their own, they only understand plain JavaScript. We typically use the TypeScript compiler or a tool like Babel to take the JSX and make JavaScript out of it. Here’s what that code looks like as JavaScript:
React.createElement('input', {
name: 'color',
size: 6,
});
Hey, those name="color"
and size={6}
attributes are an object literal now! The first argument to createElement
is what we’re creating—a class for custom components, a tag name for HTML elements—and the second argument are the props to pass to it.
This is why TypeScript is always talking about props as object types. When it type checks the React code, it makes sure that that second argument to createElement
has a type that matches (“is assignable to”) the declared type of the component’s props.
(Because it just transforms things into plain JavaScript, JSX is sometimes referred to as “syntactic sugar.” It’s not actually necessary—we could write those createElement
statements ourselves—but it makes the code sweeter.)
Now back to declaring props types
Let’s remember where we were:
interface CustomInputProps {
fieldName: string;
}class CustomInput extends React.Component<CustomInputProps> {
render() {
return <input name={this.props.fieldName} />;
}
}
Now that we’ve declared the interface
we want—the “shape” of our component’s props—we need to actually tell TypeScript to use it for CustomInput
. That’s where the theReact.Component<CustomInputProps>
comes in. The <…>
bits let us pass a type parameter. Think of it as a way of tweaking React.Component
, kind of like how you use (…)
s to pass arguments to functions. ReactComponent
uses its first type parameter as the type for this.props
, replacing the default {}
.
We can go back to our render
method and see what this.props
is now. In Visual Studio Code, you can hover over it:

React.Component<CustomInputProps, {}, any>
— This is Visual Studio telling us whatthis
is. It closely matches theextends React.Component<CustomInputProps>
from our class declaration, just with the default values forCustomInputProps
’s 2 additional type parameters written out explicitly..props:
— Because that’s what we’re hovering over.Readonly<{ children?: React.ReactNode; }> & Readonly<CustomInputProps>
— Remember thisReadonly
stuff from before? Now it hasCustomInputProps
instead of{}
.
Cool! With this change, this.props
keeps the previous children
property, but now also has everything from CustomInputProps
, in particular the fieldName
property.
There’s also state
Using this.state
is nearly identical to this.props
, so I won’t go into it in depth. The errors you get from it should be basically the same. To give a component’s state a type, use the second type parameter to React.Component
, like so:
interface Props {
fieldName: string;
}interface State {
error: string | null;
}class CustomInput extends React.Component<Props, State> {
state = {
error: null;
};
}
The above example also shows initializing state
with a default value. You could also do this with this.state = {…}
in the constructor()
method. I’ve also shortened the interface names to “Props
” and “State
” so they don’t wrap. They can actually be anything, as long as you’re consistent between the interface
and the React.Component<…>
.
Required props on a custom component
Let’s go back to using our CustomInput
component. This will be similar to when we were making <input>
elements.
Remember where we left off with CustomInput
:
interface CustomInputProps {
fieldName: string;
}class CustomInput extends React.Component<CustomInputProps> {
…
}
Let’s make one!
render() {
return (
<form>
<CustomInput />
</form>
);
}
And the error is…

It just keeps getting more complicated, doesn’t it?
Type '{}'
— To explain this, remember how JSX works. Our above line of code turns intoReact.createElement(CustomInput, {})
.{}
because we didn’t write any props in the JSX.Type '{}'
is TypeScript describing that second, props argument.is not assignable to
— The old standby. There’s an inconsistency in the types!'IntrinsicAttributes & IntrinsicClassAttributes<CustomInput> & Readonly<{ children?: ReactNode; }>...'
— This is such a mess that TypeScript literally gives up and stops before it gets to the end. The “intrinsic” bits cover common React props likekey
andref
. You can see theReadonly<{ children?: ReactNode; }>
at the end, which is the start of thethis.props
type we saw before. The complete type here is:IntrinsicAttributes & IntrinsicClassAttributes<CustomInput> & Readonly<{ children?: ReactNode; }> & Readonly<CustomInputProps>
, but honestly you can glaze over this line.Type '{}' is not assignable to type 'Readonly<CustomInputProps>'
— Here TypeScript calls out what part of theIntrinsicAttributes & … & …
it’s having trouble with.{}
is perfectly assignable toIntrinsicAttributes
,IntrinsicClassAttributes
, andReadonly<{ children?: ReactNode; }>
because all of their fields are optional. What it’s not assignable to is ourCustomInputProps
.Property 'fieldName' is missing in type '{}'.
— This is the most useful part of the error message. Thetype '{}'
is calling back to that secondcreateElement
argument, the type of the props from the JSX.
The fix: Once again, type errors are flagging inconsistencies in the code. As written, CustomInput
wants a fieldName
prop, but you’re not giving it one. So, either give it one, or make it not want one in the first place. Let’s look at how we would do each.
To pass fieldName
, we do this:
<CustomInput fieldName="myField" />
After the JSX translation, that turns into:
React.createElement(CustomInput, { fieldName: "myField" });
The type of that second, props argument is { fieldName: string }
which is assignable to CustomInputProps
.
Here’s the other case, making fieldName
optional. For this, we need to change the interface
where CustomInputProps
was declared.
interface CustomInputProps {
fieldName?: string;
}
See how there’s a ?
there now? That tells TypeScript that this property is optional. Now both { fieldName: string }
and {}
are assignable to CustomInputProps
.
This does mean that this.props.fieldName
now has the type 'string | undefined'
, so TypeScript will make you take that into account in the rest of your code. No calling this.props.fieldName.length
without checking that it’s defined first!
Passing unknown props
Finally, let’s look at the error messages you get when you give a prop to a custom component that isn’t in its props type. TypeScript has two different error messages, depending on what other props you pass.
<CustomInput fieldName="myField" placeholder="Type here" />

This error message is the same one we got with nmae
in the early example, just with CustomInput
’s longer props type at the end. It is very unfortunate that this is cut off before it says CustomInputProps
, because that’s a piece of information that would really help track down what’s going on. Just remember that when you see this, it’s most likely that the prop you’re passing it isn’t defined in the component’s own props interface.
Curiously, if we leave off fieldName
, the error message is different:
export interface CustomInputProps {
fieldName?: string;
}<CustomInput placeholder="Type here" />;

We can see the { placeholder: string; }
type from the createElement
statement that’s behind the scenes, and the IntrinsicAttributes & …
type for CustomInput
’s props. It’s just for a reason I don’t know TypeScript says “has no properties in common” rather than “does not exist.”
The fix: Resolve the inconsistency! Either add placeholder
to CustomInputProps
or remove it from <CustomInput … />
.
Whew!
There we go. Explanations for the most common TypeScript errors you run into in your React JSX, and how you might solve them. Hopefully that will reduce any future rage when programming.
I will admit that finding new ways for type checking to catch errors is one of my favorite programming exercises. In the new Boards and Commissions codebase, we’re using ts2gql
to turn TypeScript interfaces into a GraphQL schema, which means we can use those TypeScript interfaces to very precisely typecheck our resolvers. Just as with the Registry webapp, we’re using apollo-codegen
to generate argument and output types for GraphQL queries, and we’ve also added sql-ts
to make TypeScript types from SQL Server tables.
It’s a good reminder to me, and anyone else who’s putting tooling together, that a guard rail is only as good as whether or not you can tell what it’s guarding against.
Acknowledgements
Guillaume Marceau, way back in his grad school days, helped me understand how type errors arise from two conflicting parts of a program. James Duffy proofread this article.
And of course to John, for powering through all of this like a champ.
Last updated
Was this helpful?