JSX Flashcards

1
Q

What is JSX?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What are the necessary steps to use JSX in TypeScript?

A

To use JSX in TypeScript, you must:

  1. Name your files with a .tsx extension
  2. Enable the jsx compiler option in your TypeScript configuration.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What are the different JSX modes in TypeScript and what are their outputs?

A

TypeScript supports several JSX modes:

  1. preserve: Keeps the JSX as part of the output for further transformation. The output file will have a .jsx extension.
  2. react: Emits React.createElement. The output doesn’t need further JSX transformation and will have a .js extension.
  3. react-native: Equivalent to preserve, but the output will have a .js extension.
  4. react-jsx: Transforms JSX to '_jsx("div", {}, void 0);'. The output file has a .js extension.
  5. react-jsxdev: Transforms JSX to '_jsxDEV("div", {}, void 0, false, {...}, this);'. The output file has a .js extension.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

How do you specify the JSX mode and JSX factory function in TypeScript?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Why does TypeScript disallow angle bracket type assertions in .tsx files?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is the alternative to angle bracket type assertions in .tsx files?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is the difference between intrinsic elements and value-based elements in JSX type checking?

A

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 well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

How does TypeScript distinguish between intrinsic and value-based elements in JSX?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What are intrinsic elements in TypeScript JSX?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

How are intrinsic elements type checked in TypeScript JSX?

A

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
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What happens if the JSX.IntrinsicElements interface is not specified in TypeScript JSX?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How can a catch-all string indexer be used in JSX.IntrinsicElements interface in TypeScript JSX?

A

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;
  }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What are value-based elements in TypeScript JSX?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

How does TypeScript resolve value-based elements in JSX?

A

In TypeScript, there are two ways to define a value-based element:

  1. Function Component (FC) and
  2. 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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What happens if TypeScript fails to resolve a value-based element as a Function Component?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is a Function Component in TypeScript?

A

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.

17
Q

How do you define props for a Function Component in TypeScript?

A

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} />;
}
18
Q

Can you use function overloads with Function Components in TypeScript? If so, provide an example.

A

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 {
  // ...
}
19
Q

What are the element class type and element instance type in TypeScript when dealing with JSX?

A
  • The element class type is the type of the component, such as a class or function, used in a JSX expression.
  • The element instance type is determined by the return types of the class type’s construct or call signatures.
21
Q

Provide an example of determining element class type and instance type for both a class component and a factory function in TypeScript.

A
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 }
21
Q

What conditions must the element instance type meet in TypeScript and JSX? What happens if it doesn’t meet these conditions?

A

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.

22
Q

Provide an example of a valid and invalid class component and factory function according to JSX.ElementClass.

A
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
23
Q

How does attribute type checking work for intrinsic elements in JSX with TypeScript?

A

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
24
Q

How does attribute type checking work for value-based elements in JSX with TypeScript?

A

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" />;
25
Q

What happens if an attribute name is not a valid JavaScript identifier in JSX with TypeScript?

A

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.

26
Q

How does the spread operator work with attribute type checking in JSX with TypeScript?

A

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
27
Q

How can you set the type of children prop in a TypeScript/React component?

A

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>
);
28
Q

What does React.ReactNode mean in TypeScript?

A

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.

29
Q

Can the children prop include multiple JSX elements in TypeScript?

A

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.

30
Q

What will happen if the children prop doesn’t match its defined type in TypeScript?

A

If the actual children prop doesn’t match its defined type, TypeScript will throw a compile-time error, preventing you from making the mistake.

31
Q

What is the correct way to embed JavaScript expressions in JSX?

A

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.

32
Q

What error does the following JSX code produce, and why?

const a = (
  <div>
    {["foo", "bar"].map((i) => (
      <span>{i / 2}</span>
    ))}
  </div>
);
A

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.

33
Q

How can you map an array to JSX elements in TypeScript?

A

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.

34
Q

What do you need to use JSX with React in TypeScript?

A

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
    ...
  },
  ...
}
35
Q

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>;
  }
}
A

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.