如何根据 JavaScript 值推断类型

huangapple go评论78阅读模式
英文:

How do you infer type base on javascript value

问题

以下是您要翻译的代码部分:

interface Props {
    type: 'product' | 'content';
}

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    const queryClient = useQueryClient();
    const [filterSelector] = useState(() => {
        switch (props.type) {
            case 'product':
                return new ProductFilter(t, queryClient);
            case 'content':
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}
This hook works fine but the problem is that I can't get strict type inference
For example If developer provides "product" for an arguments 

const { filterSelector } = useFilterSelector({ type : "product"})

The infered type should be 

type = ProductFilter

 but i get 

type = ProductFilter | ContentFilter
I tried this

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    type FilterType = (typeof props)['type'];
    type FilterSelector = FilterType extends 'product'
        ? ProductFilter
        : FilterType extends 'content'
        ? ContentFilter
        : unknown;

    const queryClient = useQueryClient();
    const [filterSelector] = useState<FilterSelector>(() => {
        switch (props.type) {
            case 'product':
                return new ProductFilter(t, queryClient);
            case 'content':
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}
but the type is inferred as unknown

how do i fix this?

如果您需要进一步的解释或帮助,请随时提出。

英文:

I have this react hook which returns filter based on type props user gave.

interface Props {
    type: &#39;product&#39; | &#39;content&#39;;
}

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    const queryClient = useQueryClient();
    const [filterSelector] = useState(() =&gt; {
        switch (props.type) {
            case &#39;product&#39;:
                return new ProductFilter(t, queryClient);
            case &#39;content&#39;:
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}

This hook works fine but the problem is that I can't get strict type inference
For example If developer provides "product" for an arguments

  const { filterSelector } = useFilterSelector({ type : &quot;product&quot;})

The infered type should be

type = ProductFilter

but i get

type = ProductFilter | ContentFilter

I tried this

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    type FilterType = (typeof props)[&#39;type&#39;];
    type FilterSelector = FilterType extends &#39;product&#39;
        ? ProductFilter
        : FilterType extends &#39;content&#39;
        ? ContentFilter
        : unknown;

    const queryClient = useQueryClient();
    const [filterSelector] = useState&lt;FilterSelector&gt;(() =&gt; {
        switch (props.type) {
            case &#39;product&#39;:
                return new ProductFilter(t, queryClient);
            case &#39;content&#39;:
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}

but the type is inferred as unknown

how do i fix this?

答案1

得分: 1

你可以根据props.type的类型使用条件返回类型。

interface Props {
    type: 'product' | 'content';
}

interface ProductFilter {
  a: string;
}
interface ContentFilter {
  b: number;
}

interface FilterSelector<T extends Props> {
  filterSelector: T['type'] extends 'product' ? ProductFilter : ContentFilter
}

function useFilterSelector<T extends Props>(props: T): FilterSelector<T> {
  return { filterSelector: {} as any }
}

const pF = useFilterSelector({ type: 'product' })
pF.filterSelector.a
//               ^? (property) ProductFilter.a: string
const cF = useFilterSelector({ type: 'content' })
cF.filterSelector.b
//               ^? (property) ContentFilter.b: number

Playground链接

英文:

You can make use of conditional return type based on type of props.type

interface Props {
    type: &#39;product&#39; | &#39;content&#39;;
}

interface ProductFilter {
  a: string;
}
interface ContentFilter {
  b: number;
}

interface FilterSelector&lt;T extends Props&gt; {
  filterSelector: T[&#39;type&#39;] extends &#39;product&#39; ? ProductFilter : ContentFilter
}

function useFilterSelector&lt;T extends Props&gt;(props: T): FilterSelector&lt;T&gt; {
  return { filterSelector: {} as any }
}

const pF = useFilterSelector({ type: &#39;product&#39; })
pF.filterSelector.a
//               ^? (property) ProductFilter.a: string
const cF = useFilterSelector({ type: &#39;content&#39; })
cF.filterSelector.b
//               ^? (property) ContentFilter.b: number

Playground link

答案2

得分: 0

How about type assertion so that typescript will use the type instead of unknown?

switch (props.type) {
  case 'product':
    return new ProductFilter(t, queryClient) as FilterSelector;
  case 'content':
    return new ContentFilter(t, queryClient) as FilterSelector;
}
英文:

How about type assertion so that typescript will use the type instead of unknown?

switch (props.type) {
      case &#39;product&#39;:
        return new ProductFilter(t, queryClient) as FilterSelector;
      case &#39;content&#39;:
        return new ContentFilter(t, queryClient) as FilterSelector;
    }

huangapple
  • 本文由 发表于 2023年4月17日 09:53:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031237.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定