`keyof` 不会缩小过去的 `string | 范围数量 |符号`

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

我无法将 TypeScript 缩小到类型的文字键:

type Area = "local" | "sync";

type AreaMap = {
  local: { lorem: number; ipsum: boolean };
  sync: { foo: string; bar: symbol };
};

type Foo = {
  [Kind in keyof AreaMap]: {
    [Prop in keyof AreaMap[Kind]]?: Prop;
  };
};

// This is a very gross simplification of what I'm trying to do.
// The type of the values in the objects `local` and `sync` wouldn't be
// the keys themselves, but would depend on them, so this is good enough
// to demonstrate the problem.
const foo: Foo = { local: { lorem: "lorem" }, sync: {} };

function fn<A extends Area, K extends keyof AreaMap[A]>(area: A, key: K) {
  // `key` is narrowed down to `string | number | symbol` instead of `lorem | ipsum` or `foo | bar`
  // depending on the value of `area` like I expect
  thisTakesString(key);
  //              ^^^
  //              Argument of type 'string | number | symbol' is not assignable to parameter of type 'string'.
  //              Type 'number' is not assignable to type 'string'.

  foo[area][key] = key;
  //^^^^^^^^^^^^
  // Type 'K' is not assignable to type 'Foo[A][K]'.
  // Type 'keyof AreaMap[A]' is not assignable to type 'Foo[A][K]'.
  //  Type 'string | number | symbol' is not assignable to type 'Foo[A][K]'.
  //    Type 'string' is not assignable to type 'Foo[A][K]'.
  return { area, key };
}

function thisTakesString(value: string) {}

我需要根据

key
的值将
fn
内的
"lorem" | "ipsum"
缩小为
"foo" | "bar"
area
,但由于某种原因,
key
fn
的类型是
string | number | symbol

编辑:根据@jcalz的建议,我将按照this来缩小

key
我需要的范围。我过去实际上已经使用过它,但想看看是否有另一种方法,因为我不想添加额外的属性,因为数据将存储在一个非常小的限制的数据库中。

typescript keyof
1个回答
0
投票

您需要简化您的类型并做一些工作。

type Local = { lorem: number; ipsum: boolean };

type Sync = { foo: string; bar: symbol };

type Foo = {
    local?: Local,
    sync?: Sync
};

const foo: Foo = {};

function fn<T extends keyof Foo, K extends keyof Foo[T]>(area: T, key: K) {
    
    thisTakesString(key);  // expected Argument of type 'string | number | symbol' is not assignable to parameter of type 'string'.

    if(foo[area]){
        //return foo[area][key]; // error Type 'K' cannot be used to index type 'Local | Sync'
        return (foo[area])[key]; // work
    }

    return (foo[area])[key]; // expected Object is possibly 'undefined'
}

function thisTakesString(value: string) { }
© www.soinside.com 2019 - 2024. All rights reserved.