函数不返回嵌套keyof的值

时间:2019-02-17 20:04:48

标签: typescript

我正在尝试从模型级别之一返回值。第一层完美地工作,因为返回值的类型为T [K],这意味着['Login','Password','Address']返回我想要的内容。但是当我改变 getProperty(auth, x => x.Address);getProperty(auth, x => x.Address.Address2);。 我知道'Address2'属性不是直接在T类型下。 我不知道哪种类型的更改'T [K]'也可以使用。 Address2属性。 你能帮我吗?

编辑:getProperty(auth, x => x.Address.Address2.State);的怪异之处

export interface Auth {
  Login: string;
  Password: string;
  Address: {
      Address2: {
        State: string;
      }
  }
}

let auth: Auth = {
    Login: 'login',
    Password: 'password',
    Address: {
        Address2:{
            State: 'some state'
        }
    }
  };


function getProperty<T, K extends keyof T>(obj: T, fn: (m: T) => T[K]) {
    console.log(fn(obj));
}

getProperty(auth, x => x.Address.Address2);

2 个答案:

答案 0 :(得分:1)

function getProperty<T, B>(obj: T, fn: (m: T) => B): B {
   return fn(obj);
}

const testType = getProperty(auth, x => x.Address.Address2); // string.

希望这会有所帮助,据我所知,无法对类型进行加深的事实是您的函数返回由T的索引产生的类型,因为无法表示此“加深”。 I.E您可以表达T [K],但只能达到1的深度。可以完全表达深度键访问的另一种语法如下:

interface IGetProperty<Original, Access> {
    value: Access,
    pick: <K extends keyof Access>(key: K) => IGetProperty<Original, Access[K]>
}

const getProperty = <Original, Access = Original>(obj: Original): IGetProperty<Original, Access> => {
   return {
       value: obj as any,
       pick: (key) => getProperty((obj as any)[key as any]) as any
   }
}

const testType = getProperty(auth).pick("Address").pick("Address2").pick("State").value // string.
const testType = getProperty(auth).pick("Address").pick("Invalid Key").pick("State").value // Error.

编辑:在打字稿中,即使您可以键入一个函数返回T [K],也不会“强制”该函数返回一些从“ T”索引的值,因为如果T [K]是字符串,那么您可以返回任何字符串,例如不是来自“ T”的“ hello”,它仍然会进行类型检查,这是因为如果您使用的是T [K]的类型,那么Typescript键入的东西在结构上并不是名义上的,则这种行为是可能的在全球范围内

答案 1 :(得分:0)

我不是100%确信我理解用例,但是您可以使用运行时不存在的幻像类型,将回调限制为“返回(可能嵌套的)属性的东西”。像这样:

object

这个想法是,我们假装传入的对象不是 declare class DeepDooDoo {private dooDoo: true}; type DeepVooDoo<T> = DeepDooDoo & (T extends object ? { [K in keyof T]: DeepVooDoo<T[K]> } : T) function getProperty<T, U>(obj: T, fn: (m: DeepVooDoo<T>)=>DeepVooDoo<U> ): void { console.log(fn(obj as DeepVooDoo<T>)); } 类型,而是T类型。这是幻影类DeepVooDoo<T>的实例,并且(由于递归映射类型定义),其所有属性本身都是DeepDooDoo实例,并且它们的所有属性,等等。回调函数受到限制到接受DeepDooDoo并为某些DeepVooDoo<T>返回DeepVooDoo<U>的事物。这或多或少意味着您必须返回传入对象的属性或子属性(或子子属性等)。如果尝试返回其他内容,则编译器可能会注意到不是U并抱怨。

让我们尝试一下:

DeepDooDoo

看起来很好。幻像类型有点滥用类型系统,因此很可能会产生奇怪的副作用。如果您决定继续执行此类操作,请小心操作并确保它适合您的用例。

好的,希望能有所帮助。祝你好运!