打字稿:使用接受组件实例的外部函数进行React渲染

问题描述 投票:0回答:1

我正在创建一堆内部具有一些常用功能的组件,其中一个是处理渲染的组件。简化,它看起来像这样:

const render = (
    instance: React.Component<{}, {flag: boolean}>,
    cb: () => React.ReactNode
) => instance.state.flag ? cb() : '';

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() { return render(this, () => '') }
}

但是,TypeScript对此设置不满意并说:'render' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.就个人而言,我看不到这个参考。

作为一个可能的线索,如果我这样重写这段代码:

const render = (
    state: {flag: boolean},
    cb: () => React.ReactNode
) => state.flag ? cb() : '';

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() { return render(this.state, () => '') }
}

...一切运作良好,但我真的想要使用组件本身,因为现在看不到一些复杂性。

有什么问题?我能用这个常用功能做些什么来让TypeScript不争论吗?


UPD:一些测试让我创建了一个更接近所需的示例:

type Component<T> = React.Component<{}, {flag: T}>
const render = <T>(
    instance: Component<T>,
    cb: () => React.ReactNode
) => instance.state.flag ? cb() : '';

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() {
        const result = render(this, () => '');
        return result;
    }
    inner = () => 'test';
}

这里的要点是外部render函数是通用的,instance类型取决于泛型参数,因此TypeScript无法替换正确的参数来代替T。是否有可能在不失去类型安全的情况下帮助他?

reactjs typescript type-inference
1个回答
1
投票

这里的问题似乎是渲染函数中实例参数的类型推断。

让我们来看看

  • 即使你将实例类型标记为React.Component,当typescript尝试推断渲染类型时,它必须使用必须为React.Component <>的'this'实例,要做到这一点,它也必须ckech渲染类成员,并且回来开始。所以我认为打字稿决定放弃这个推论
type RenderF = (
    instance: React.Component<any, any>,
    cb: () => React.ReactNode) => React.ReactNode;

const render: RenderF = (
    instance: React.Component<{}, {flag: boolean}>,
    cb: () => React.ReactNode
) => instance.state.flag ? cb() : null;

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() { return render(this, () => null) }
}
  • 因此,一个简单的解决方案是将RenderF实例参数标记为任意参数,以避免打字稿推断再次检查实例。
type RenderF = (
    instance: any, // <-----
    cb: () => React.ReactNode) => React.ReactNode;

const render: RenderF = (
    instance: React.Component<{}, {flag: boolean}>,
    cb: () => React.ReactNode
) => instance.state.flag ? cb() : null;

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() { return render(this, () => null) }
}

UPD

如果您不想在实例参数中放松类型安全性,则只能在新类型中指定所需的内容

interface FlagComponent {
    state: { flag: boolean }
}

type RenderF = (
    instance: FlagComponent,
    cb: () => React.ReactNode) => React.ReactNode;

const render: RenderF = (
    instance: React.Component<{}, {flag: boolean}>,
    cb: () => React.ReactNode
) => instance.state.flag ? cb() : null;

class Test extends React.Component<{}, {flag: boolean}> {
    state = {flag: true};
    render() { return render(this, () => null) }
}
© www.soinside.com 2019 - 2024. All rights reserved.