JSX Flashcards
What is JSX?
JSX is an embeddable XML-like syntax. It is meant to be transformed into valid JavaScript.
TypeScript supports embedding, type checking, and compiling JSX directly to JavaScript. JSX is used widely in frameworks like React and it allows HTML/XML-like syntax to be used in JavaScript code.
“Documentation - JSX” (typescriptlang.org). Retrieved June 28, 2023.
What are the necessary steps to use JSX in TypeScript?
To use JSX in TypeScript, you must:
- Name your files with a
.tsx
extension - Enable the
jsx
compiler option in your TypeScript configuration.
“JSX Basic usage” (typescriptlang.org). Retrieved June 28, 2023.
What are the different JSX modes in TypeScript and what are their outputs?
TypeScript supports several JSX modes:
-
preserve
: Keeps the JSX as part of the output for further transformation. The output file will have a.jsx
extension. -
react
: EmitsReact.createElement
. The output doesn’t need further JSX transformation and will have a.js
extension. -
react-native
: Equivalent to preserve, but the output will have a.js
extension. -
react-jsx
: Transforms JSX to'_jsx("div", {}, void 0);'
. The output file has a.js
extension. -
react-jsxdev
: Transforms JSX to'_jsxDEV("div", {}, void 0, false, {...}, this);'
. The output file has a.js
extension.
“JSX Basic usage” (typescriptlang.org). Retrieved June 28, 2023.
How do you specify the JSX mode and JSX factory function in TypeScript?
The JSX mode can be specified using the 'jsx'
command line flag or the corresponding 'jsx'
compiler option in your tsconfig.json file.
To specify the JSX factory function (which defaults to React.createElement
when targeting react
JSX emit), you can use the 'jsxFactory'
compiler option in your TypeScript configuration.
“JSX Basic usage” (typescriptlang.org). Retrieved June 28, 2023.
Why does TypeScript disallow angle bracket type assertions in .tsx
files?
TypeScript disallows angle bracket type assertions in .tsx
files because TypeScript also uses angle brackets for type assertions, which would introduce certain parsing difficulties when combined with JSX’s syntax.
“JSX, The as operator” (typescriptlang.org). Retrieved June 28, 2023.
What is the alternative to angle bracket type assertions in .tsx
files?
The as
operator.
For instance,
const foo = bar as foo;
asserts that the variable bar
is of type foo
. The as
operator is identical in behavior to the angle-bracket type assertion style.
“JSX, The as operator” (typescriptlang.org). Retrieved June 28, 2023.
What is the difference between intrinsic elements and value-based elements in JSX type checking?
In JSX type checking, intrinsic elements refer to elements that are intrinsic to the environment, such as a div
or span
in a DOM environment. On the other hand, value-based elements refer to custom components created by the user.
Intrinsic elements are emitted as strings in React (React.createElement("div")
), while value-based elements (components created by the user) are not (React.createElement(MyComponent)
). Furthermore, the types of the attributes being passed in the JSX element are looked up differently for each. Attributes for intrinsic elements should be known intrinsically, whereas components may want to specify their own set of attributes.
In TypeScript and React, an intrinsic element always begins with a lowercase letter, while a value-based element always begins with an uppercase letter.
“JSX Type Checking” Retrieved July 3, 2023.
How does TypeScript distinguish between intrinsic and value-based elements in JSX?
TypeScript uses the same convention that React does for distinguishing between intrinsic and value-based elements in JSX. An intrinsic element always begins with a lowercase letter, while a value-based element (a custom component) always begins with an uppercase letter.
“JSX Type Checking” Retrieved July 3, 2023.
What are intrinsic elements in TypeScript JSX?
Intrinsic elements in TypeScript JSX refer to elements that are intrinsic to the environment, such as a div
or span
in a DOM environment. They are looked up on the special interface JSX.IntrinsicElements
.
“JSX Intrinsic elements” (typescriptlang.org). Retrieved July 3, 2023.
How are intrinsic elements type checked in TypeScript JSX?
Intrinsic elements in TypeScript JSX are type checked using the JSX.IntrinsicElements
interface. If this interface is present, the name of the intrinsic element is looked up as a property on the JSX.IntrinsicElements
interface. For example, if the interface declares a foo
property, <foo />
will pass type checking but <bar />
will fail as it’s not declared in the interface.
For example:
declare namespace JSX { interface IntrinsicElements { foo: any; } } <foo />; // ok <bar />; // error
“JSX Intrinsic elements” (typescriptlang.org). Retrieved July 3, 2023.
What happens if the JSX.IntrinsicElements
interface is not specified in TypeScript JSX?
If the JSX.IntrinsicElements
interface is not specified in TypeScript JSX, then intrinsic elements will not be type checked. This means any intrinsic element name can be used without causing an error.
“JSX Intrinsic elements” (typescriptlang.org). Retrieved July 3, 2023.
How can a catch-all string indexer be used in JSX.IntrinsicElements
interface in TypeScript JSX?
A catch-all string indexer can be used on the JSX.IntrinsicElements
interface to accept any string as an element name. This is done as follows:
declare namespace JSX { interface IntrinsicElements { [elemName: string]: any; } }
“JSX Intrinsic elements” (typescriptlang.org). Retrieved July 3, 2023.
What are value-based elements in TypeScript JSX?
Value-based elements in TypeScript JSX refer to custom components that you’ve created. These elements are looked up by identifiers that are in scope.
For example, if you import and use MyComponent
from "./myComponent"
, <MyComponent />
will be ok. But using an undefined component like <SomeOtherComponent />
will result in an error.
“JSX Value-based elements” (typescriptlang.org). Retrieved July 3, 2023.
How does TypeScript resolve value-based elements in JSX?
In TypeScript, there are two ways to define a value-based element:
- Function Component (FC) and
- Class Component.
In JSX expressions, Function Component and Class Component are indistinguishable from each other. Thus, TypeScript first tries to resolve the expression as a Function Component using overload resolution. If that process succeeds, TypeScript finishes resolving the expression to its declaration.
“JSX Value-based elements” (typescriptlang.org). Retrieved July 3, 2023.
What happens if TypeScript fails to resolve a value-based element as a Function Component?
If TypeScript fails to resolve a value-based element as a Function Component, it then tries to resolve it as a Class Component. If that also fails, TypeScript will report an error.
“JSX Value-based elements” (typescriptlang.org). Retrieved July 3, 2023.
What is a Function Component in TypeScript?
In TypeScript, a Function Component is a JavaScript function where its first argument is a props object, and its return type must be assignable to JSX.Element
.
“Function Component” (typescriptlang.org). Retrieved July 3, 2023.
How do you define props for a Function Component in TypeScript?
You can define props for a Function Component by creating an interface that describes the shape of the props object.
For example:
interface FooProp { name: string; X: number; Y: number; } function ComponentFoo(prop: FooProp) { return <AnotherComponent name={prop.name} />; }
“Function Component” (typescriptlang.org). Retrieved July 3, 2023.
Can you use function overloads with Function Components in TypeScript? If so, provide an example.
Yes, you can use function overloads with Function Components in TypeScript.
For example:
interface ClickableProps { children: JSX.Element[] | JSX.Element; } interface HomeProps extends ClickableProps { home: JSX.Element; } interface SideProps extends ClickableProps { side: JSX.Element | string; } function MainButton(prop: HomeProps): JSX.Element; function MainButton(prop: SideProps): JSX.Element; function MainButton(prop: ClickableProps): JSX.Element { // ... }
“Function Component” (typescriptlang.org). Retrieved July 3, 2023.
What are the element class type and element instance type in TypeScript when dealing with JSX?
- The element class type is the type of the component, such as a
class
orfunction
, used in a JSX expression. - The element instance type is determined by the return types of the class type’s construct or call signatures.
“Class Component” (typescriptlang.org). Retrieved July 4, 2023.
Provide an example of determining element class type and instance type for both a class component and a factory function in TypeScript.
class MyComponent { render() {} } // use a construct signature const myComponent = new MyComponent(); // element class type => MyComponent // element instance type => { render: () => void } function MyFactoryFunction() { return { render: () => {}, }; } // use a call signature const myComponent = MyFactoryFunction(); // element class type => MyFactoryFunction // element instance type => { render: () => void }
“Class Component” (typescriptlang.org). Retrieved July 4, 2023.
What conditions must the element instance type meet in TypeScript and JSX? What happens if it doesn’t meet these conditions?
The element instance type must be assignable to JSX.ElementClass
or it will result in an error. By default JSX.ElementClass
is {}, but it can be augmented to limit the use of JSX to only those types that conform to the proper interface.
“Class Component” (typescriptlang.org). Retrieved July 4, 2023.
Provide an example of a valid and invalid class component and factory function according to JSX.ElementClass
.
declare namespace JSX { interface ElementClass { render: any; } } class MyComponent { render() {} } function MyFactoryFunction() { return { render: () => {} }; } <MyComponent />; // ok <MyFactoryFunction />; // ok class NotAValidComponent {} function NotAValidFactoryFunction() { return {}; } <NotAValidComponent />; // error <NotAValidFactoryFunction />; // error
“Class Component” (typescriptlang.org). Retrieved July 4, 2023.
How does attribute type checking work for intrinsic elements in JSX with TypeScript?
For intrinsic elements, the attribute type is determined by the type of the property on JSX.IntrinsicElements
. For example:
declare namespace JSX { interface IntrinsicElements { foo: { requiredProp: string; optionalProp?: number }; } } <foo requiredProp="bar" />; // ok <foo requiredProp="bar" optionalProp={0} />; // ok <foo />; // error, requiredProp is missing <foo requiredProp={0} />; // error, requiredProp should be a string <foo requiredProp="bar" unknownProp />; // error, unknownProp does not exist <foo requiredProp="bar" some-unknown-prop />; // ok, because 'some-unknown-prop' is not a valid identifier
“JSX Attribute type checking” (typescriptlang.org). Retrieved July 5, 2023.
How does attribute type checking work for value-based elements in JSX with TypeScript?
For value-based elements, the attribute type is determined by the type of a property on the element instance type. Which property to use is determined by JSX.ElementAttributesProperty
. It should be declared with a single property, and the name of that property is then used.
For example:
declare namespace JSX { interface ElementAttributesProperty { props; // specify the property name to use } } class MyComponent { // specify the property on the element instance type props: { foo?: string; }; } // element attributes type for 'MyComponent' is '{foo?: string}' <MyComponent foo="bar" />;
“JSX Attribute type checking” (typescriptlang.org). Retrieved July 5, 2023.
What happens if an attribute name is not a valid JavaScript identifier in JSX with TypeScript?
If an attribute name is not a valid JavaScript identifier (like a data-*
attribute), it is not considered to be an error if it is not found in the element attributes type.
“JSX Attribute type checking” (typescriptlang.org). Retrieved July 5, 2023.
How does the spread operator work with attribute type checking in JSX with TypeScript?
The spread operator can be used to pass attributes to a JSX element. If the properties in the spread object don’t match the expected attributes of the JSX element, an error will be thrown.
For example:
declare namespace JSX { interface IntrinsicElements { foo: { requiredProp: string; optionalProp?: number }; } } const props = { requiredProp: "bar" }; <foo {...props} />; // ok const badProps = {}; <foo {...badProps} />; // error
“JSX Attribute type checking” (typescriptlang.org). Retrieved July 5, 2023.
How can you set the type of children prop in a TypeScript/React component?
You can set the type of children in your component’s prop types. For example, if you want to enforce that children should be a single React element, you can do so like this:
interface MyComponentProps { children: React.ReactNode; } const MyComponent: React.FC<MyComponentProps> = ({ children }) => ( <div>{children}</div> );
“JSX Children Type Checking” (typescriptlang.org). Retrieved July 6, 2023.
What does React.ReactNode
mean in TypeScript?
React.ReactNode
is a type provided by React’s TypeScript definitions. It is used to represent any thing that can be rendered in React. This can include strings
, numbers
, JSX elements
, arrays
of these things, or functions returning these things.
“JSX Children Type Checking” (typescriptlang.org). Retrieved July 6, 2023.
Can the children prop include multiple JSX elements in TypeScript?
Yes, if the children prop type is set to React.ReactNode
or JSX.Element[]
, it can include multiple JSX elements. If it’s set to JSX.Element
, it can only include one JSX element.
“JSX Children Type Checking” (typescriptlang.org). Retrieved July 6, 2023.
What will happen if the children prop doesn’t match its defined type in TypeScript?
If the actual children prop doesn’t match its defined type, TypeScript will throw a compile-time error, preventing you from making the mistake.
“JSX Children Type Checking” (typescriptlang.org). Retrieved July 6, 2023.
What is the correct way to embed JavaScript expressions in JSX?
JavaScript expressions can be embedded in JSX by wrapping them in curly braces ({ }
). For example:
const element = <h1>Hello, {user.name}</h1>;
In this case, user.name
is a JavaScript expression embedded in JSX.
“Embedding Expressions” (typescriptlang.org). Retrieved July 6, 2023.
What error does the following JSX code produce, and why?
const a = ( <div> {["foo", "bar"].map((i) => ( <span>{i / 2}</span> ))} </div> );
This code will throw a runtime error because it attempts to divide a string (i
) by a number. In JavaScript, you cannot perform mathematical operations on a string and a number without first converting the string to a number.
“Embedding Expressions” (typescriptlang.org). Retrieved July 6, 2023.
How can you map an array to JSX elements in TypeScript?
You can map an array to JSX elements by using the JavaScript map function inside a JSX expression. However, remember to return a JSX element from the callback function. For instance:
class MyComponent extends React.Component<Props, {}> { render() { const array = [1, 2, 3]; const listItems = array.map((num) => (<li key={num}>{num}</li>)); return <ul>{listItems}</ul>; } }
In this case, each item in the array is mapped to an <li>
element.
“Embedding Expressions” (typescriptlang.org). Retrieved July 6, 2023.
What do you need to use JSX with React in TypeScript?
To use JSX with React in TypeScript, you need to set up your TypeScript configuration (tsconfig.json
) to correctly interpret JSX syntax, and include the necessary React type definitions.
Install the necessary types for React and React-DOM:
npm install --save-dev @types/react @types/react-dom
Next, ensure your tsconfig.json
file includes the following:
{ "compilerOptions": { "jsx": "react", // Enable JSX ... }, ... }
“React integration” (typescriptlang.org). Retrieved July 7, 2023.
Given the following TypeScript React component, what is the result of <MyComponent foo={0} />
?
interface Props { foo: string; } class MyComponent extends React.Component<Props, {}> { render() { return <span>{this.props.foo}</span>; } }
This would result in a TypeScript error. According to the Props interface, foo
is expected to be of type string
. But in <MyComponent foo={0} />
, foo is given a number (0
), hence the type error.
“React integration” (typescriptlang.org). Retrieved July 7, 2023.