@avantstay/graphql-ts-client 10.7.0 → 11.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/endpoint.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -3
- package/dist/types-4ada662b.d.ts +70 -0
- package/package.json +1 -1
- package/src/__testClient.d.ts +164 -0
- package/src/__testClient.js +119 -0
- package/src/generateTypescriptClient.ts +1 -2
- package/src/types.ts +5 -2
package/dist/endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ClientConfig, I as IResponseListener, E as Endpoint } from './types-
|
|
1
|
+
import { C as ClientConfig, I as IResponseListener, E as Endpoint } from './types-4ada662b.js';
|
|
2
2
|
|
|
3
3
|
declare const getApiEndpointCreator: (apiConfig: {
|
|
4
4
|
getClient: () => ClientConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PathLike } from 'fs';
|
|
2
|
-
export { C as ClientConfig, c as DeepReplace, D as Defined, E as Endpoint, G as GraphQLClientError, I as IResponseListener, J as JsonOutput, L as LogInfo, M as Maybe, P as Projection, d as RawEndpoint, b as Replacement, R as ResponseData, a as ResponseListenerInfo, U as Unpacked } from './types-
|
|
2
|
+
export { C as ClientConfig, c as DeepReplace, D as Defined, E as Endpoint, G as GraphQLClientError, I as IResponseListener, J as JsonOutput, L as LogInfo, M as Maybe, P as Projection, d as RawEndpoint, b as Replacement, R as ResponseData, a as ResponseListenerInfo, U as Unpacked } from './types-4ada662b.js';
|
|
3
3
|
|
|
4
4
|
type IClientOptions = {
|
|
5
5
|
output?: PathLike;
|
package/dist/index.js
CHANGED
|
@@ -487,7 +487,7 @@ var prettier = __toESM(require("prettier"));
|
|
|
487
487
|
// package.json
|
|
488
488
|
var package_default = {
|
|
489
489
|
name: "@avantstay/graphql-ts-client",
|
|
490
|
-
version: "
|
|
490
|
+
version: "11.0.0-beta.1",
|
|
491
491
|
description: "GraphQL Typescript Client Generator",
|
|
492
492
|
author: "Wellington Guimaraes",
|
|
493
493
|
license: "MIT",
|
|
@@ -683,8 +683,7 @@ function gqlEndpointToCode(kind, endpoint, codeOutputType) {
|
|
|
683
683
|
var outputType = gqlTypeToTypescript(endpoint.type, {
|
|
684
684
|
required: true
|
|
685
685
|
});
|
|
686
|
-
|
|
687
|
-
return codeOutputType === "ts" ? "".concat(endpoint.name, ": Endpoint<").concat(inputType, ", ").concat(wrappedOutputType, ", AllEnums>") : "".concat(endpoint.name, ": apiEndpoint('").concat(kind, "', '").concat(endpoint.name, "')");
|
|
686
|
+
return codeOutputType === "ts" ? "".concat(endpoint.name, ": Endpoint<").concat(inputType, ", ").concat(outputType, ", AllEnums>") : "".concat(endpoint.name, ": apiEndpoint('").concat(kind, "', '").concat(endpoint.name, "')");
|
|
688
687
|
}
|
|
689
688
|
function gqlSchemaToCode(gqlType, param) {
|
|
690
689
|
var _param_selection = param.selection, selection = _param_selection === void 0 ? false : _param_selection, outputType = param.outputType;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
type Maybe<T> = null | undefined | T;
|
|
2
|
+
type Defined<T> = Exclude<T, undefined>;
|
|
3
|
+
type ResponseData = {
|
|
4
|
+
data: any;
|
|
5
|
+
warnings: any;
|
|
6
|
+
headers: any;
|
|
7
|
+
status?: number;
|
|
8
|
+
errors: {
|
|
9
|
+
message: string;
|
|
10
|
+
}[];
|
|
11
|
+
};
|
|
12
|
+
type ResponseListenerInfo = {
|
|
13
|
+
queryName: string;
|
|
14
|
+
query: string;
|
|
15
|
+
variables: any;
|
|
16
|
+
response: ResponseData;
|
|
17
|
+
};
|
|
18
|
+
type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
|
|
19
|
+
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
|
|
20
|
+
type Primitive = Date | string | number | boolean | null | undefined;
|
|
21
|
+
type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Primitive | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Primitive | E ? Selection extends undefined ? Base | undefined : Base : {
|
|
22
|
+
[k in keyof Selection & keyof Base]: Selection[k] extends boolean ? Base[k] : Base[k] extends Array<infer A> ? Projection<Defined<Selection[k]>, A, E>[] : Projection<Defined<Selection[k]>, Base[k], E>;
|
|
23
|
+
};
|
|
24
|
+
type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
|
|
25
|
+
type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
|
|
26
|
+
type DeepReplace<T, Ignore, M extends [any, any]> = {
|
|
27
|
+
[P in keyof T]: T[P] extends M[0] ? T[P] extends Ignore ? T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P] : Replacement<M, T[P]> : T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P];
|
|
28
|
+
};
|
|
29
|
+
type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
|
|
30
|
+
data: Projection<S, O, E>;
|
|
31
|
+
errors: any[];
|
|
32
|
+
warnings: any[];
|
|
33
|
+
headers: any;
|
|
34
|
+
status: any;
|
|
35
|
+
}>;
|
|
36
|
+
type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
|
|
37
|
+
type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
|
|
38
|
+
memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
|
|
39
|
+
memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
|
|
40
|
+
raw: RawEndpoint<I, JsonOutput<O, E>, E>;
|
|
41
|
+
};
|
|
42
|
+
type ClientConfig = {
|
|
43
|
+
url: string;
|
|
44
|
+
headers: {
|
|
45
|
+
[key: string]: string;
|
|
46
|
+
};
|
|
47
|
+
retryConfig: {
|
|
48
|
+
max: number;
|
|
49
|
+
waitBeforeRetry?: number;
|
|
50
|
+
before: IResponseListener;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
type LogInfo = {
|
|
54
|
+
query: string;
|
|
55
|
+
variables: any;
|
|
56
|
+
formatGraphQL: any;
|
|
57
|
+
kind: string;
|
|
58
|
+
queryName: string;
|
|
59
|
+
response?: any;
|
|
60
|
+
error?: Error;
|
|
61
|
+
duration: number;
|
|
62
|
+
};
|
|
63
|
+
declare class GraphQLClientError extends Error {
|
|
64
|
+
responseData: ResponseData;
|
|
65
|
+
constructor(responseData: ResponseData);
|
|
66
|
+
get message(): string;
|
|
67
|
+
get response(): ResponseData;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IResponseListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, Unpacked as U, ResponseListenerInfo as a, Replacement as b, DeepReplace as c, RawEndpoint as d };
|
package/package.json
CHANGED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
|
|
2
|
+
import { DeepRequired } from "ts-essentials"
|
|
3
|
+
import { Maybe, IResponseListener, Endpoint } from "."
|
|
4
|
+
|
|
5
|
+
// Scalars
|
|
6
|
+
export type IDate = string | Date
|
|
7
|
+
export declare type ISODate = IDate
|
|
8
|
+
|
|
9
|
+
// Enums
|
|
10
|
+
|
|
11
|
+
export declare enum BookType {
|
|
12
|
+
dolor = "DOLOR",
|
|
13
|
+
ipsum = "IPSUM",
|
|
14
|
+
sit = "SIT",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type AllEnums = BookType
|
|
18
|
+
|
|
19
|
+
// Args
|
|
20
|
+
export interface BooksWithoutParamsArgs {}
|
|
21
|
+
export interface BooksWithOptionalParamsArgs {
|
|
22
|
+
params?: BookSearchParamsAllOptional
|
|
23
|
+
}
|
|
24
|
+
export interface BooksWithRequiredParamsArgs {
|
|
25
|
+
params: BookSearchParamsSomeRequired
|
|
26
|
+
}
|
|
27
|
+
export interface FailingQueryArgs {
|
|
28
|
+
id: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Input/Output Types
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
export interface Image {
|
|
38
|
+
url?: string
|
|
39
|
+
alt?: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export interface Book {
|
|
47
|
+
title?: string
|
|
48
|
+
author?: string
|
|
49
|
+
type?: BookType
|
|
50
|
+
dateCreated?: ISODate
|
|
51
|
+
images?: Image[]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export interface BookSearchParamsAllOptional {
|
|
59
|
+
title?: string
|
|
60
|
+
author?: string
|
|
61
|
+
createdAfter?: ISODate
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
export interface BookSearchParamsSomeRequired {
|
|
69
|
+
title: string
|
|
70
|
+
author?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
export interface Query {
|
|
78
|
+
booksWithoutParams?: Book[]
|
|
79
|
+
booksWithOptionalParams?: Book[]
|
|
80
|
+
booksWithRequiredParams?: Book[]
|
|
81
|
+
failingQuery?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Selection Types
|
|
85
|
+
|
|
86
|
+
export interface ImageSelection {
|
|
87
|
+
url?: boolean
|
|
88
|
+
alt?: boolean
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface BookSelection {
|
|
92
|
+
title?: boolean
|
|
93
|
+
author?: boolean
|
|
94
|
+
type?: boolean
|
|
95
|
+
dateCreated?: boolean
|
|
96
|
+
images?: ImageSelection
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface BookSearchParamsAllOptionalSelection {
|
|
100
|
+
title?: boolean
|
|
101
|
+
author?: boolean
|
|
102
|
+
createdAfter?: boolean
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface BookSearchParamsSomeRequiredSelection {
|
|
106
|
+
title?: boolean
|
|
107
|
+
author?: boolean
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export declare const myApiClient: {
|
|
111
|
+
addResponseListener: (listener: IResponseListener) => void
|
|
112
|
+
setHeader: (key: string, value: string) => void
|
|
113
|
+
setHeaders: (newHeaders: { [k: string]: string }) => void
|
|
114
|
+
setUrl: (url: string) => void
|
|
115
|
+
setRetryConfig: (options: {
|
|
116
|
+
max: number
|
|
117
|
+
waitBeforeRetry?: number
|
|
118
|
+
before?: IResponseListener
|
|
119
|
+
}) => void
|
|
120
|
+
queries: {
|
|
121
|
+
booksWithoutParams: Endpoint<
|
|
122
|
+
{
|
|
123
|
+
__headers?: { [key: string]: string }
|
|
124
|
+
__retry?: boolean
|
|
125
|
+
__alias?: string
|
|
126
|
+
} & BookSelection,
|
|
127
|
+
Book[],
|
|
128
|
+
AllEnums
|
|
129
|
+
>
|
|
130
|
+
booksWithOptionalParams: Endpoint<
|
|
131
|
+
{
|
|
132
|
+
__headers?: { [key: string]: string }
|
|
133
|
+
__retry?: boolean
|
|
134
|
+
__alias?: string
|
|
135
|
+
__args?: BooksWithOptionalParamsArgs
|
|
136
|
+
} & BookSelection,
|
|
137
|
+
Book[],
|
|
138
|
+
AllEnums
|
|
139
|
+
>
|
|
140
|
+
booksWithRequiredParams: Endpoint<
|
|
141
|
+
{
|
|
142
|
+
__headers?: { [key: string]: string }
|
|
143
|
+
__retry?: boolean
|
|
144
|
+
__alias?: string
|
|
145
|
+
__args: BooksWithRequiredParamsArgs
|
|
146
|
+
} & BookSelection,
|
|
147
|
+
Book[],
|
|
148
|
+
AllEnums
|
|
149
|
+
>
|
|
150
|
+
failingQuery: Endpoint<
|
|
151
|
+
{
|
|
152
|
+
__headers?: { [key: string]: string }
|
|
153
|
+
__retry?: boolean
|
|
154
|
+
__alias?: string
|
|
155
|
+
__args: FailingQueryArgs
|
|
156
|
+
},
|
|
157
|
+
string,
|
|
158
|
+
AllEnums
|
|
159
|
+
>
|
|
160
|
+
}
|
|
161
|
+
mutations: {}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export default myApiClient
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
__markAsModule(target);
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __reExport = (target, module2, desc) => {
|
|
14
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(module2))
|
|
16
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
17
|
+
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
var __toModule = (module2) => {
|
|
22
|
+
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
|
|
23
|
+
};
|
|
24
|
+
__export(exports, {
|
|
25
|
+
BookType: () => BookType,
|
|
26
|
+
default: () => stdin_default,
|
|
27
|
+
myApiClient: () => myApiClient
|
|
28
|
+
});
|
|
29
|
+
var import_endpoint = __toModule(require("./endpoint"));
|
|
30
|
+
var import_standalone = __toModule(require("prettier/standalone"));
|
|
31
|
+
var import_parser_graphql = __toModule(require("prettier/parser-graphql"));
|
|
32
|
+
const formatGraphQL = (query) => (0, import_standalone.format)(query, { parser: "graphql", plugins: [import_parser_graphql.default] });
|
|
33
|
+
const BookType = {
|
|
34
|
+
dolor: "DOLOR",
|
|
35
|
+
ipsum: "IPSUM",
|
|
36
|
+
sit: "SIT"
|
|
37
|
+
};
|
|
38
|
+
const typesTree = {
|
|
39
|
+
Query: {
|
|
40
|
+
get booksWithOptionalParams() {
|
|
41
|
+
return {
|
|
42
|
+
__fields: typesTree.Book,
|
|
43
|
+
__args: {
|
|
44
|
+
params: "BookSearchParamsAllOptional!"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
get booksWithRequiredParams() {
|
|
49
|
+
return {
|
|
50
|
+
__fields: typesTree.Book,
|
|
51
|
+
__args: {
|
|
52
|
+
params: "BookSearchParamsSomeRequired!"
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
get failingQuery() {
|
|
57
|
+
return {
|
|
58
|
+
__args: {
|
|
59
|
+
id: "String!"
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
get booksWithoutParams() {
|
|
64
|
+
return {
|
|
65
|
+
__fields: typesTree.Book
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
Book: {
|
|
70
|
+
images: {}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
let verbose = false;
|
|
74
|
+
let headers = {};
|
|
75
|
+
let url = "http://localhost:4123/graphql";
|
|
76
|
+
let retryConfig = {
|
|
77
|
+
max: 0,
|
|
78
|
+
before: void 0,
|
|
79
|
+
waitBeforeRetry: 0
|
|
80
|
+
};
|
|
81
|
+
let responseListeners = [];
|
|
82
|
+
let errorsParser = void 0;
|
|
83
|
+
let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
|
|
84
|
+
getClient: () => ({ url, headers, retryConfig }),
|
|
85
|
+
responseListeners,
|
|
86
|
+
maxAge: 3e4,
|
|
87
|
+
verbose,
|
|
88
|
+
typesTree,
|
|
89
|
+
formatGraphQL,
|
|
90
|
+
errorsParser
|
|
91
|
+
});
|
|
92
|
+
const myApiClient = {
|
|
93
|
+
addResponseListener: (listener) => responseListeners.push(listener),
|
|
94
|
+
setHeader: (key, value) => {
|
|
95
|
+
headers[key] = value;
|
|
96
|
+
},
|
|
97
|
+
setHeaders: (newHeaders) => {
|
|
98
|
+
headers = newHeaders;
|
|
99
|
+
},
|
|
100
|
+
setRetryConfig: (options) => {
|
|
101
|
+
if (!Number.isInteger(options.max) || options.max < 0) {
|
|
102
|
+
throw new Error("retryOptions.max should be a non-negative integer");
|
|
103
|
+
}
|
|
104
|
+
retryConfig = {
|
|
105
|
+
max: options.max,
|
|
106
|
+
waitBeforeRetry: options.waitBeforeRetry,
|
|
107
|
+
before: options.before
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
setUrl: (_url) => url = _url,
|
|
111
|
+
queries: {
|
|
112
|
+
booksWithoutParams: apiEndpoint("query", "booksWithoutParams"),
|
|
113
|
+
booksWithOptionalParams: apiEndpoint("query", "booksWithOptionalParams"),
|
|
114
|
+
booksWithRequiredParams: apiEndpoint("query", "booksWithRequiredParams"),
|
|
115
|
+
failingQuery: apiEndpoint("query", "failingQuery")
|
|
116
|
+
},
|
|
117
|
+
mutations: {}
|
|
118
|
+
};
|
|
119
|
+
var stdin_default = myApiClient;
|
|
@@ -152,10 +152,9 @@ function gqlEndpointToCode(kind: 'mutation' | 'query', endpoint: IntrospectionFi
|
|
|
152
152
|
}${selectionType ? ` & ${selectionType}` : ''}`
|
|
153
153
|
|
|
154
154
|
const outputType = gqlTypeToTypescript(endpoint.type, { required: true })
|
|
155
|
-
const wrappedOutputType = /^(string|number|boolean)$/.test(outputType) ? outputType : `DeepRequired<${outputType}>`
|
|
156
155
|
|
|
157
156
|
return codeOutputType === 'ts'
|
|
158
|
-
? `${endpoint.name}: Endpoint<${inputType}, ${
|
|
157
|
+
? `${endpoint.name}: Endpoint<${inputType}, ${outputType}, AllEnums>`
|
|
159
158
|
: `${endpoint.name}: apiEndpoint('${kind}', '${endpoint.name}')`
|
|
160
159
|
}
|
|
161
160
|
|
package/src/types.ts
CHANGED
|
@@ -21,11 +21,14 @@ export type IResponseListener = (info: ResponseListenerInfo) => void | Promise<v
|
|
|
21
21
|
|
|
22
22
|
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never
|
|
23
23
|
|
|
24
|
+
type Primitive = Date | string | number | boolean | null | undefined
|
|
25
|
+
|
|
26
|
+
// Projection is the resulting type of Selection (type generated out of a query) applied to Base (generated graphql type)
|
|
24
27
|
export type Projection<Selection, Base, E = never> = Base extends Array<any>
|
|
25
|
-
? ArrayElement<Base> extends
|
|
28
|
+
? ArrayElement<Base> extends Primitive | E
|
|
26
29
|
? ArrayElement<Base>[]
|
|
27
30
|
: Projection<Defined<Selection>, ArrayElement<Base>, E>[]
|
|
28
|
-
: Base extends
|
|
31
|
+
: Base extends Primitive | E
|
|
29
32
|
? // Is primitive and extends undefined
|
|
30
33
|
Selection extends undefined
|
|
31
34
|
? Base | undefined
|