简体   繁体   English

如何在 Typescript 中覆盖不可为空的属性

[英]How to override a property to be non-nullable in Typescript

The DefinitelyTyped definition of the Node built-in IncomingMessage (the type of req in the (req, res, next) arguments) has defined url to be nullable . Node 内置 IncomingMessage ( (req, res, next)参数中的 req 类型)的 distinctTyped 定义已将url定义为 nullable Here's the snipped parts of the definition file:这是定义文件的片段:

// @types/node/index.d.ts
declare module "http" {
  export interface IncomingMessage {
    /**
     * Only valid for request obtained from http.Server.
     */
    url?: string;
  }
}

As the comment says, this is because this property is only valid when you're getting an instance of this IncomingMessage from the http.Server.正如评论所说,这是因为此属性仅在您从 http.Server 获取此 IncomingMessage 的实例时才有效。 In other uses it won't exist, hence, it's nullable.在其他用途​​中,它不会存在,因此它可以为空。

However, in my case, I know that I'm only getting these instances from http.Server, and so it's kinda annoying that I can't just access the property without extra guards.但是,就我而言,我知道我只是从 http.Server 获取这些实例,所以我不能在没有额外保护的情况下访问该属性,这有点烦人。

import { IncomingMessage, ServerResponse } from 'http';

function someMiddleware(req: IncomingMessage, res: ServerResponse, next: Function) {
  const myStr: string = req.url; // bzzzt.
  // Argument of type 'string | undefined' is not
  // assignable to parameter of type 'string'.
}

It's probably good to mention that I'm using TS 2.0.3 with strictNullChecks , which is not enabled on the Typescript Playground .值得一提的是,我正在使用带有strictNullChecks的 TS 2.0.3, Typescript Playground上没有启用它。

Here's the question.这是问题。 Is it possible to override that definition across my application so that url is not nullable?是否可以在我的应用程序中覆盖该定义以使url不可为空?


Here's what I've already tried... adding this to one of my files:这是我已经尝试过的...将其添加到我的一个文件中:

declare module 'http' {
  interface IncomingMessage {
    url: string;
  }
}

...however that is disallowed: "Subsequent variable declarations must have the same type". ...但是这是不允许的:“后续变量声明必须具有相同的类型”。 This is explained in the documentation. 这在文档中进行了解释。

The only thing I can think of thus far is to create my own module which imports, extends and then exports the interfaces:到目前为止,我唯一能想到的就是创建自己的模块来导入、扩展然后导出接口:

// /src/http.ts
import { IncomingMessage as OriginalIM } from 'http';
export interface IncomingMessage extends OriginalIM {
  url: string;
}

// src/myapp.ts
import { IncomingMessage } from './http'; // <-- local def

function someMiddleware(req: IncomingMessage) {
  const str: string = req.url; // all good
}

So, this works, but it seems so wrong.所以,这行得通,但它似乎是错误的。

Here's a solution defining a utility type RequiredProperties :这是定义实用程序类型RequiredProperties的解决方案:

type RequiredProperties<T, P extends keyof T> = Omit<T, P> & Required<Pick<T, P>>;

type Foo = {
    a?: any;
    b?: any;
    c?: any;
};

type Bar = RequiredProperties<Foo, 'a' | 'b'>;

const bar1: Bar = { a: 1, b: 2, c: 3 };
const bar2: Bar = { b: 2, c: 3 }; // fails because `a` is now required
const bar3: Bar = { c: 3 }; // fails because both `a` and `b` are missing

So I found a solution which is slightly less hacky. 因此,我找到了一个解决方案,它的hacky 稍差一些。

TypeScript 2.0 also has added a non-null assertion operator : ! 打字稿2.0还增加了一个非空的断言操作!

function someMiddleware(req: IncomingMessage) {
  const str1: string = req.url;  // error, can't assign string | undefined to string
  const str2: string = req.url!; // works
}

In my case, it's still a bit annoying, since there are many different files which need to access this property and so this non-null assertion is used in many places. 就我而言,这仍然有点烦人,因为有许多不同的文件需要访问此属性,因此在许多地方都使用了这种非null断言。

As of TypeScript 2.1, you can use a lookup type to access an interface property. 从TypeScript 2.1开始,您可以使用查找类型来访问接口属性。

IncomingMessage['url'] // string | undefined

You can combine that with NonNullable to fit your use case. 您可以将其与NonNullable结合起来以适合您的用例。

NonNullable<IncomingMessage['url']> // string

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

In your sample case, it's easy because you want to get rid of ALL undefined , therefore use the Required utility type.在您的示例案例中,这很容易,因为您想摆脱 ALL undefined ,因此使用Required实用程序类型。

interface IncomingMessage { url?: string; }
type ValidMessage = Required<IncomingMessage>;

ValidMessage will have all properties required . ValidMessage 将具有required的所有属性。

But for those coming here to find out how to get rid of ALL null , you can use this custom utility type.但是对于那些来这里了解如何摆脱 ALL null的人,您可以使用此自定义实用程序类型。

export type NonNullableFields<T> = {
  [P in keyof T]: NonNullable<T[P]>;
};

interface IncomingMessage { url: string | null; }
type ValidMessage = NonNullableFields<IncomingMessage>;

ValidMessage will have all properties not null . ValidMessage 将具有not null的所有属性。

And for those coming here to find out how to get rid of null only for specific fields, you can use these custom utility types.对于那些来这里了解如何仅针对特定字段摆脱null的人,您可以使用这些自定义实用程序类型。

export type NonNullableFields<T> = {
  [P in keyof T]: NonNullable<T[P]>;
};

export type NonNullableField<T, K extends keyof T> = T &
NonNullableFields<Pick<T, K>>;

interface IncomingMessage { url: string | null; }
type ValidMessage = NonNullableField<IncomingMessage, 'url'>;

ValidMessage will have the property url not null . ValidMessage 将具有属性url not null

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

相关问题 GraphQL中的可选但不可为空的字段 - Optional but non-nullable fields in GraphQL 无法在续集中插入具有不可为空外键的行 - Unable to insert row with non-nullable foreign key in sequelize 错误:无法为不可为空的 postgress 返回 null - Error: Cannot return null for non-nullable postgress 阿波罗服务器+续集错误不可为空的字段 - apollo server + sequelize error non-nullable field Apollo GraphQL“无法为不可为空的字段 Mutation.createUser 返回 null” - Apollo GraphQL "Cannot return null for non-nullable field Mutation.createUser" 错误:不能为不可为空的字段 Post.title 返回 null - Error: Cannot return null for non-nullable field Post.title GraphQL 的不可为空错误没有提供太多细节,这可能让我进行调查 - Non-nullable error with GraphQL doesn't give much detail which might allow me to investigate GraphQL 错误:无法为不可为空的字段 Mutation.deleteComment 返回 null - GraphQL Error: Cannot return null for non-nullable field Mutation.deleteComment 无法为不可为空的字段 Mutation.createUser 返回 null - Apollo Server - Cannot return null for non-nullable field Mutation.createUser - Apollo Server 无法为不可为空的字段 Mutation.createAds graphql 错误返回 null - Cannot return null for non-nullable field Mutation.createAds graphql error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM