[英]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.