适当缩小 Solid.js 中的访问器类型

Properly narrowing down accessor type in Solid.js

我有一个 Solid.js 代码,看起来像这样

import { render } from "solid-js/web";
import { createSignal , Component } from "solid-js";

const Number: Component<{value: number}> = ({value}) => <b>{value}</b> 

const App: Component = () => {
  const [foo] = createSignal<number | null>(null);

  return (
    foo() 
      ? <Number value={foo()} /> /* foo() is number | null, causing an error */
      : <div>foo is null</div>
  );
}

render(() => <App />, document.getElementById("app")!);

如何正确缩小 foo() 访问器的类型,以便我可以安全地将其作为 Number 的属性传递?

在普通变量上,三元运算符适当地缩小了类型:

let bar!: number | null;

bar 
    ? <Number value={bar} /> // bar's type is narrowed from number | null to number
    : <div>bar is null</div>

但它似乎不适用于存取器变量

Playground

您可以使用 Show 组件来缩小类型

import { render } from "solid-js/web";
import { createSignal, Component, Show } from "solid-js";

const Number: Component<{value: number}> = ({value}) => <b>{value}</b> 

const App: Component = () => {
  const [foo] = createSignal<number | null>(null);

  return (
    <Show when={foo()} fallback={<div>foo is null</div>}>
      {(f) => <Number value={f} />}
    </Show>
  );
}

render(() => <App />, document.getElementById("app")!);

Playground

缩小类型和渲染值是两个不同的概念。您在三元组中使用的条件不够具体,无法消除 non-number 值。如果您使用正确的条件 typeof val() === 'number',typescript 将正确计算类型。

const Num: Component<{ value: number }> = (props) => {
  return <div>{props.value}</div>
}

const App = () => {
  const [val] = createSignal<number | null>(null);

  return (
    <div>
      {typeof val() === 'number' ? <Num value={val()} /> : <div>{val()}</div>}
    </div>
  );
};

否则,缩小类型范围的最直接方法是强制转换,val() as number,但它会抑制给您误报的类型。当您知道类型但打字稿无法识别时,您应该使用转换。

已接受答案中的 Show 组件不会缩小类型范围,而是将 when 值强制转换为布尔值并相应地呈现提供的元素。如果你检查它的类型它是 Show<T> 这意味着任何。您正在寻找的是基于值类型的条件渲染。

Solid 将 JSX 用于其 UI 层,因此您可以使用表达式有条件地渲染项目,JSX 规范中描述的方式:无论您从大括号 [=22= 之间的表达式 return ] 将打印在屏幕上,除非它是一个虚假值。

您可以使用 && 运算符有条件地呈现 element/component:

const App = () => {
  const myVal = 'two';
  return (
    <div>
      {myVal === 'one' && <div>One</div>}
      {myVal === 'two' && <div>One</div>}
      {myVal === 'three' && <div>One</div>}
    </div>
  );
};

您可以使用三元运算符来决定两个 elements/components:

const App = () => {
  const isLoggedIn = true;
  return (
    <div>
      {isLoggedIn ? (
        <Logout onClick={handleLogout} />
      ) : (
        <Login onClick={handleLogin} />
      )}
    </div>
  );
};

因此,在最基本的方式中,您可以使用 typeof 运算符来过滤仅数字值:

const App = () => {
  const [val] = createSignal<number | null>(0);

  return (
    <div>
      {typeof val() === 'number' ? <div>number: {val()}</div> : <div>Not a number</div>}
    </div>
  );
};

Solid 提供 built-in Show 组件,用于根据两个互斥条件渲染元素,就像我们使用三元运算符一样。结果将被记忆以减少下游渲染。

<Show when={true} fallback={<Fallback />}>
  <div>My Content</div>
</Show>

它还需要一个渲染函数:

<Show when={state.count} fallback={<div>Loading...</div>}>
  {(props) => <div>{props.count}</div>}
</Show>

这里是如何使用 Show 组件来实现的:

const App = () => {
  const [val] = createSignal<number | null>(null);

  return (
    <Show when={typeof val() === 'number'} fallback={<div>Not a number</div>}>
      <div>number: {val()}</div>
    </Show>
  );
};

还有<Switch>/<Match>根据自定义条件渲染元素:

<Switch fallback={<div>Aww Week Day!</div>}>
  <Match when={state.day === "saturday"}>
    <Saturday />
  </Match>
  <Match when={state.day === "sundat"}>
    <Sunday />
  </Match>
</Switch>