簡體   English   中英

為什么在 union 中使用的對象的屬性的類型是 any?

[英]Why does the property of an object used in the union has the type any?

我有一個包含 3 個道具的組件: toValuefromValuechildren 其中前 2 個是可選的,但如果指定了其中一個,則還必須指定另一個。 children prop 是一個具有inputProps參數的函數,它應該等於toValue函數的返回類型 ( TInputValue ),如果指定的話,或者TStateValue

我寫了下面的代碼,但我不明白為什么在指定toValue函數的情況下inputPropsany 如何解決?

interface IP<T> {
  value: T
  onChange: (value: T) => void
}
interface A<TStateValue> {
  toValue?: never
  fromValue?: never
  children: (inputProps: IP<TStateValue>) => null
}
interface B<TStateValue, TInputValue>  {
  toValue: (value: TStateValue) => TInputValue
  fromValue: (value: TInputValue) => TStateValue
  children: (inputProps: IP<TInputValue>) => null
}
type C<TStateValue, TInputValue> =
  | A<TStateValue>
  | B<TStateValue, TInputValue>

const propsWithoutToValue: C<number, string> = {
  children: (inputProps) => null, // `inputProps` is `IP<number>`. Nice!
}
const propsWithToValue: C<number, string> = {
  toValue: (value) => value.toString(), // The return type is a `string`, so the `inputProps` must be `IP<string>`
  fromValue: (value) => Number(value),
  children: (inputProps) => null, // `inputProps` is any, but must be `IP<string>`. How to fix it?
}

我已經為我要解決的問題創建了一個回購協議: https ://github.com/oxilor/form-types

快速解決方案:

interface IP<T> {
  value: T
  onChange: (value: T) => void
}
interface A<TStateValue> {
  type:"A",
  children(inputProps: IP<TStateValue>, a:1) : null
}
interface B<TStateValue, TInputValue>  {
  type: "B",
  toValue: (value: TStateValue) => TInputValue
  fromValue: (value: TInputValue) => TStateValue
  children(inputProps: IP<TInputValue>) : null
}

type C<TStateValue, TInputValue> =
  | B<TStateValue, TInputValue>
  | A<TStateValue>

const propsWithoutToValue: C<number, string> = {
  type: "A",
  children: (inputProps) => null,
  //          ^?
}
const propsWithToValue: C<number, string> = {
  type: "B",
  toValue: (value) => value.toString(), 
  fromValue: (value) => Number(value),
  children: (inputProps) => null,
  //            ^?
}

在此處輸入圖像描述

操場

//========================觀察===========

A 點:如果您嘗試聯合 2 個具有不同參數類型的函數,則參數類型為any

在此處輸入圖像描述

重要更新:為什么函數“聯合”參數顯示為any但實際上never或其他

B 點:打字稿認為您嘗試聯合 2 個函數的原因是因為具有相同對象屬性的聯合函數的行為方式與兩個函數的聯合相同

在此處輸入圖像描述

這基本上意味着{b:((a:1)=>void)} | {b:((a:number)=>void)} {b:((a:1)=>void)} | {b:((a:number)=>void)}字面意思是{b:((a:1)=>void) | ((a:number)=>void)} {b:((a:1)=>void) | ((a:number)=>void)}

有幾件事我無法解釋:

  1. A點和B點所示行為背后的理由(目的是什么)
  2. 似乎受歧視的聯合(或一般的聯合)不能與函數類型一起正常工作(或不能本能地工作)
  3. A點不適用於propsWithoutToValue,但適用於propsWithToValue,很有可能是point 2的后效

這是使用條件類型的替代方法。

我們這里有兩種通用類型。 類型決定了提供給children的道具。 我將其稱為TChildProps並將其放在首位,因為它始終存在。

然后是僅在情況B中相關的類型TStateValue

在情況A中,您的狀態可以直接提供給toValue ,因此不需要childrenfromValue轉換器函數。

條件說如果狀態可以直接傳遞給childrenTStateValue extends TChildProps )那么我們處於情況A 如果狀態是不同的類型,那么我們處於情況B並且必須提供轉換器。

type C<TChildProps, TStateValue = TChildProps> =
  TStateValue extends TChildProps ? A<TStateValue> : B<TStateValue, TChildProps>

C上的泛型與您之前的泛型略有不同。

對於propsWithoutToValue ,我們只需要number類型。

const propsWithoutToValue: C<number> = {
  children: (inputProps) => null, // `inputProps` is `IP<number>`. Nice!
}

propsWithToValue的情況下,兩個泛型的順序現在顛倒了。

const propsWithToValue: C<string, number> = {
  toValue: (value) => value.toString(),
  fromValue: (value) => Number(value),
  children: (inputProps) => null, // `inputProps` is `IP<string>`.  We did it!
}

第一個通用類型參數string將使inputProps具有類型IP<string>

由於第二個泛型類型參數number不能分配給string ,我們必須提供一個將number轉換為stringtoValue函數和一個將string轉換為numberfromValue函數。

打字稿游樂場鏈接

解決這個問題的一種方法是只聲明一種接口類型並將兩個屬性設置為可選,並且從不返回類型。 這里的一個問題是兩個鍵總是可選的,即 toValue 和 fromValue

interface IP<T> {
  value: T
  onChange: (value: T) => void
}

interface IProps<TStateValue, TInputValue> {
  toValue?: (value: TStateValue) => TInputValue | never
  fromValue?: (value: TInputValue) => TStateValue | never
  children: (inputProps: IP<TInputValue>) => null
}

const propsWithoutToValue: IProps<number, string> = {
  children: (inputProps) => null
}
const propsWithToValue: IProps<number, string> = {
  toValue: (value) => value.toString(),
  fromValue: (value) => Number(value),
  children: (inputProps) => null
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM