【问题标题】:how to define a literal type based on a value inside an object如何根据对象内部的值定义文字类型
【发布时间】:2019-06-19 01:32:31
【问题描述】:

在流程中,我可以像这样定义一个动态文字类型:

const myVar = 'foo'

type X = {
  [typeof myVar]: string
}

const myX: X = { foo: 1 } // will throw, because number
const myX: X = { foo: 'bar' } // will not throw

我现在正在尝试将一些代码转换为打字稿,但这种语法是不可能的。但是,我无法弄清楚如何在打字稿中做到这一点。这是我正在使用的代码(已经部分翻译成打字稿):

type Theme = {
  fontSizes: number[]
}

type SystemObj = {
  prop: string,
  cssProperty?: string,
}

type Props<T> = T & {
  theme: Theme,
}

const style = <X>({
  prop,
  cssProperty,
}: SystemObj) => {
  const cssProp = cssProperty || prop

  return (props: Props<{
    [typeof cssProp]: X
  }>) => {
    return props
  }
}

const fontSize = style<number>({
  prop: 'fontSize',
})

fontSize({
  fontSize: 2,
  theme: {
    fontSizes: [12, 14, 16],
  }
})

当前抛出(在打字稿游乐场上打开所有选项)

Argument of type '{ fontSize: number; theme: { fontSizes: number[]; }; }' is not assignable to parameter of type '{ theme: Theme; }'.
  Object literal may only specify known properties, and 'fontSize' does not exist in type '{ theme: Theme; }'.

编辑:

所以我让它工作,正是我希望它工作的方式:

type Theme = {
  fontSizes: number[]
}

type SystemObj = {
  prop: string,
  cssProperty?: string,
}

type Props = {
  theme: Theme,
}

const style = <X extends string, Y>({
  prop,
  cssProperty,
}: SystemObj) => {
  const cssProp = cssProperty || prop

  return (props: Props & { [K in X]: Y }) => {
    return props
  }
}

const fontSize = style<'fontSize', number>({
  prop: 'fontSize',
})

fontSize({
  fontSize: 123,
  theme: {
    fontSizes: [12, 14, 16],
  }
})

这里是否可以去掉&lt;'fontSize' 部分?:

const fontSize = style<'fontSize', number>({
  prop: 'fontSize',
})

然后输入这个

const fontSize = style<number>({
  prop: 'fontSize',
})

它完全按照我希望的方式工作,只是想知道我是否可以在此处删除重复项(因为 prop: 'fontSize' 已经定义了密钥)。这又回到了我最初的问题,我如何将值 fontSize 定义为我的类型中的键。

【问题讨论】:

  • 不完全确定您的问题是什么。你也可以在 TypeScript 中使用相同的方法。您唯一需要更改的是将[typeof myVar] 替换为[myVar]。我不太了解 Flow,但我怀疑您是否真的必须使用 [typeof myVar] 来获取 myVarcontent,因为 typeof myVar 将评估为“字符串”,而不是“foo” .
  • 嗯,就是这样,我确实希望字符串的 content 成为这里的关键。这样这部分:`return (props: Props) => { return props}`returns 的类型为{ theme: Theme, fontSize: number }
  • 我让它完全按照我现在想要的方式工作@str,但是请参阅上面的编辑,我想知道我是否可以删除const style = &lt;'fontSize' 部分,因为我传递给函数的对象定义已经有钥匙了。
  • @MartinBroder 我认为这是不可能的 atm 因为 TS 不允许泛型类型的部分显式定义:github.com/Microsoft/TypeScript/issues/10571 但您至少可以确保属性值和泛型文字是等效: type SystemObj = { prop: X, cssProperty?: string, } const style = ({ prop, cssProperty, }: SystemObj) => { const cssProp = cssProperty | | prop return (props: Props & { [K in X]: Y }) => { return props } }
  • 您能否详细说明SystemObj 的用途并展示实际用例?您只需:const style = &lt;T&gt;() =&gt; (props: Props &amp; T) =&gt; props; const fontSize = style&lt;{fontSize: number}&gt;(); 即可达到相同的效果(如在编辑示例中)

标签: javascript reactjs typescript types flowtype


【解决方案1】:

目前这是不可能的,因为您想部分指定和部分推断类型参数。一旦this PR 进入 TypeScript,您将能够执行以下操作:

type SystemObj<T extends string> = { // <------ note T here
  prop: T,
  cssProperty?: string,
}

type Props = {
  theme: Theme,
}

const style = <X extends string, Y>({
  prop,
  cssProperty,
}: SystemObj<X>) => { // <---------------------- X as an argument here
  const cssProp = cssProperty || prop

  return (props: Props & { [K in X]: Y }) => {
    return props
  }
}

const fontSize = style<_, number>({ // <-------- Ask TS to infer type param
  prop: 'fontSize',
})

fontSize({
  fontSize: 123,
  theme: {
    fontSizes: [12, 14, 16],
  }
})

【讨论】:

  • 呃,好吧。伤害我的感觉,我现在不能正确输入这个。或者可以说,不是以简单的方式。谢谢!
【解决方案2】:

如果没有部分参数类型推断,您可以将 style 函数拆分为“两部分” - style 将返回一个接受 SystemObj 的函数。这样你就可以指定值类型(number),并且道具名称将从SystemObj推断出来:

type SystemObj<TProp extends string> = {
    prop: TProp,
    cssProperty?: string,
}

const style = <TValue>() =>
    <TKey extends string>(systemObj: SystemObj<TKey>) =>
        (props: Props & { [K in TKey]: TValue }) => props

const fontSize = style<number>()({
    prop: 'fontSize',
})

fontSize({
    fontSize: 123,
    theme: {
        fontSizes: [12, 14, 16],
    }
})

Playground

【讨论】:

    猜你喜欢
    • 2021-10-19
    • 2018-12-12
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    • 2021-01-24
    • 2019-02-13
    相关资源
    最近更新 更多