简体   繁体   English

在仍能推断类型的同时,能否在此函数中获得TypeScript自动完成功能?

[英]Can I get TypeScript autocomplete in this function while still inferring types?

I am writing a set of factory functions, which will each return part of a larger overall object. 我正在编写一组工厂函数,每个工厂函数都将返回较大整体对象的一部分。 As it is a complex type, I want to be able to use intellisense to help me write these functions. 由于它是一种复杂的类型,因此我希望能够使用智能感知来帮助我编写这些功能。

I don't know what return type to annotate the functions with to ensure I get intellisense/autocomplete. 我不知道使用什么返回类型来注释函数,以确保获得智能/自动完成功能。 I have tried three things so far. 到目前为止,我已经尝试了三件事。 For these examples, you can assume FooType is defined as: 对于这些示例,可以假设FooType定义为:

interface FooType {
    prop1: boolean;
    prop2: boolean;
    ...
}

Option One 选项一

I can use type inference to automatically determine type for my functions, but then I don't get any type inference. 我可以使用类型推断来自动确定函数的类型,但是这样我就不会得到任何类型推断。

function PartialFooMaker1() {
   return {
        prop1: true,
        // I want autocomplete in here
   }
}
function PartialFooMaker2() {
   return {
        prop2: true,
        // I also want autocomplete in here
   }
}

export const Foo: FooType = Object.assign({}, PartialFooMaker1(),PartialFooMaker2());

Option Two 选项二

I can specify the full type as the function return type, but that (correctly) triggers a compile error if I omit some properties. 我可以将完整类型指定为函数返回类型,但是如果我省略一些属性,那会(正确)触发编译错误。

function PartialFooMaker1(): FooType {
   return {
        prop1: true,
        // I have autocomplete, but TS complains about the lack of prop2
   }
}
function PartialFooMaker2(): FooType {
   return {
        prop2: true,
        // I have autocomplete, but TS complains about the lack of prop1
   }
}

export const Foo: FooType = Object.assign({}, PartialFooMaker1(),PartialFooMaker2());

Option Three 选项三

I can specify the full type as the function return type, but that (correctly) triggers a compile error if I omit some properties. 我可以将完整类型指定为函数返回类型,但是如果我省略一些属性,那会(正确)触发编译错误。

function PartialFooMaker1(): Partial<FooType> {
   return {
        prop1: true,
        // I have autocomplete! :)
   }
}
function PartialFooMaker2(): Partial<FooType> {
   return {
        prop2: true,
        // I have autocomplete! :)
   }
}

// the compile error is now here - TS doesn't know that prop1 and prop2 are present
export const Foo: FooType = Object.assign({}, PartialFooMaker1(),PartialFooMaker2());

I have also considered splitting up FooType into well-defined subtypes, and then recombining with union types, but in reality it is a complex derived type, so it would be hard for me to split up. 我还考虑过将FooType拆分为定义明确的子类型,然后与并集类型重新组合,但实际上,它是一个复杂的派生类型,因此对我来说很难拆分。

Is there anything else I can try? 还有什么我可以尝试的吗?

If you can (reasonably) use Pick : 如果可以(合理地)使用Pick

interface NamePart { first: string; last: string }
interface AgePart  { age: number; }
interface FooType extends NamePart, AgePart
{
    oneMoreThing: string;
}

function PartialFooMaker1(): Pick<FooType, keyof NamePart | "oneMoreThing">
{
    return {
        first: "Steve",
        last: "Stevenson",
        oneMoreThing: "!",
    }
}
function PartialFooMaker2(): Pick<FooType, keyof AgePart>
{
    return {
        age: 42
    }
}

export const Foo: FooType = { ...PartialFooMaker1(), ...PartialFooMaker2() };

The first part will have the resolved type Pick<FooType, "first" | "last" | "oneMoreThing"> 第一部分的解析类型为Pick<FooType, "first" | "last" | "oneMoreThing"> Pick<FooType, "first" | "last" | "oneMoreThing"> Pick<FooType, "first" | "last" | "oneMoreThing"> which combines correctly with Pick<FooType, "age"> to form a complete instance of FooType . Pick<FooType, "first" | "last" | "oneMoreThing">Pick<FooType, "age">正确Pick<FooType, "age">形成FooType的完整实例。

Keys can be unioned from type-safe literals and keyof expressions. 可以从类型安全的文字和keyof表达式中keyof

Partial means zero or more properties in common. Partial表示共有零个或多个属性。 What you want is Pick : 您想要的是Pick

function PartialFooMaker1(): Pick<FooType, 'prop1'> {
  return {
       prop1: true,
       // I want autocomplete in here
  };
}

function PartialFooMaker2(): Pick<FooType, 'prop2'> {
  return {
       prop2: true,
       // I also want autocomplete in here
  };
}

Using Pick will require you to provide the properties which you want to pick in advance, but it will give you IntelliSense in return. 使用“ Pick将要求您提前提供要选择的属性,但这将为您提供IntelliSense。

Another option would be to tell TypeScript that every factory function returns a piece of FooType . 另一个选择是告诉TypeScript每个工厂函数都返回一个FooType

type Slice<T extends object> = { [P in keyof T]: Pick<T, P> }[keyof T];

type FooFactory = () => Slice<FooType>;

const PartialFooMaker3: FooFactory = () => {
  return {
    prop1: false,
  };
};

This won't require explicit return types, but the inferred type will always be a slice of FooType — not the slice of FooType you are actually returning. 这不会需要明确的返回类型,但推断出的类型将永远是一片 FooType -不是切片 FooType你实际上返回。 That's why I recommend taking the #1 approach. 这就是为什么我建议采用第一方法。 IntelliSense won't suggest what you should return if you don't say what the desired return type should be. 如果您未说明所需的返回类型,则IntelliSense不会建议您返回什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM