简体   繁体   English

TypeScript 使用泛型有条件地合并 Prop 类型

[英]TypeScript Conditionally Merge Prop Types Using Generics

Compiler tells me that properties propA and propB inside TestComponent don't exist on type Props<T> .编译器告诉我TestComponent中的属性propApropB在类型Props<T>上不存在。 Is there something I'm missing or misunderstanding about conditional types?我对条件类型有什么遗漏或误解吗?

import React from 'react';

type PropsBase<T extends boolean | undefined> = {
  isA?: T;
};

type PropsA = {
  propA: string;
};

type PropsB = {
  propB: string;
};

type Props<T extends boolean | undefined> = PropsBase<T> & (T extends false | undefined ? PropsB : PropsA);

function TestComponent<T extends boolean | undefined = true>(props: Props<T>) {
  if (props.isA) {
    return <>{props.propA}</>; // Property 'propA' does not exist
  }
  if (!props.isA) {
    return <>{props.propB}</>; // Property 'propB' does not exist
  }

  return <></>;
}

<>
  <TestComponent propA="propA" /> // Should be valid
  <TestComponent isA propA="propA" /> // Should be valid
  <TestComponent isA={false} propB="propB" /> // Should be valid
  <TestComponent isA propB="propB" /> // Should be invalid
</>

My goal was to create an extendable and reusable type which properties can be controlled through generics.我的目标是创建一个可扩展和可重用的类型,其属性可以通过泛型进行控制。 I know this is also done with unions, but it's not quite easy to build other types on top of it.我知道这也是用联合完成的,但在它之上构建其他类型并不容易。

Playground link . 游乐场链接

I think your first example of <TestComponent propA="propA" /> should also be invalid?我认为您的第一个<TestComponent propA="propA" />示例也应该无效? After all, in that case, ìsA is of type undefined`.毕竟,在那种情况下, ìsA is of type undefined 。

I changed your Props<T> into this Props instead:我把你的Props<T>改成了这个Props

type Props = ({ isA: true } & PropsA) | ({ isA?: false } & PropsB);

function TestComponent(props: Props) {
    if (props.isA) {
        return props.propA; // OK
    }
    if (!props.isA) {
        return props.propB; // OK
    }
}

Your usage of it is also validated properly now:您对它的使用现在也得到了正确验证:

TestComponent({ propA: 'propA' }); // Property 'isA' is missing
TestComponent({ propB: 'propB' }); // OK
TestComponent({ isA: true, propA: 'propA' }); // OK
TestComponent({ isA: false, propB: 'propB' }); // OK
TestComponent({ isA: true, propB: 'propB' }); // 'propB' does not exist

Interestingly, if I use prop.isA === true , TypeScript behaves better:有趣的是,如果我使用prop.isA === true ,TypeScript 的表现会更好:

function TestComponent(props: Props) {
    if (props.isA === true) {
        return props.propA; // OK
    }
    const isA = props.isA; // type `false | undefined`
    if (!props.isA) {
        return props.propB; // OK
    }
}

That should be good enough in your case I hope?我希望在你的情况下应该足够好? Although I'm surprised in the difference between if (props.isA) and if (props.isA === true) .虽然我对if (props.isA)if (props.isA === true)之间的区别感到惊讶。 Mind that this requires TypeScript to run in strict mode, with noImplicitAny enabled to be specific.请注意,这需要 TypeScript 在严格模式下运行,并启用noImplicitAny以使其特定。 Otherwise you need to use if (props.isA === true) .否则你需要使用if (props.isA === true) Weird, but running with noImplicitAny disabled is very rare anyway.很奇怪,但是在noImplicitAny禁用的情况下运行是非常罕见的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM