Allow optional inputs to be Input<T | undefined>
The Node.js runtime accepts `Output<undefined>` values as inputs to optional parameters, but the TypeScript typing currently does not allow these. This extends the TypeScript typings to allow `Output<undefined>` values as inputs to optional input properties. I cannot think of any way in which this is breaking or would regress any aspect of the TypeScript experience, other than making the `.d.ts` files a little "noisier". Fixes #6175.
This commit is contained in:
parent
ed769377dc
commit
ae70447a18
18
pkg/codegen/internal/test/testdata/types.json
vendored
18
pkg/codegen/internal/test/testdata/types.json
vendored
|
@ -58,7 +58,7 @@
|
|||
"plain": "map[string]string"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<{[key: string]: pulumi.Input<string>}> | undefined",
|
||||
"input": "pulumi.Input<{[key: string]: pulumi.Input<string>} | undefined> | undefined",
|
||||
"plain": "{[key: string]: string} | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -114,7 +114,7 @@
|
|||
"plain": "pulumi.Archive"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<pulumi.asset.Archive> | undefined",
|
||||
"input": "pulumi.Input<pulumi.asset.Archive | undefined> | undefined",
|
||||
"plain": "pulumi.asset.Archive | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -139,7 +139,7 @@
|
|||
"plain": "pulumi.AssetOrArchive"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive> | undefined",
|
||||
"input": "pulumi.Input<pulumi.asset.Asset | pulumi.asset.Archive | undefined> | undefined",
|
||||
"plain": "pulumi.asset.Asset | pulumi.asset.Archive | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -164,7 +164,7 @@
|
|||
"plain": "*bool"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<boolean> | undefined",
|
||||
"input": "pulumi.Input<boolean | undefined> | undefined",
|
||||
"plain": "boolean | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -189,7 +189,7 @@
|
|||
"plain": "*int"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<number> | undefined",
|
||||
"input": "pulumi.Input<number | undefined> | undefined",
|
||||
"plain": "number | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -239,7 +239,7 @@
|
|||
"plain": "*float64"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<number> | undefined",
|
||||
"input": "pulumi.Input<number | undefined> | undefined",
|
||||
"plain": "number | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -464,7 +464,7 @@
|
|||
"plain": "*string"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<string> | undefined",
|
||||
"input": "pulumi.Input<string | undefined> | undefined",
|
||||
"plain": "string | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -508,7 +508,7 @@
|
|||
"plain": "map[string]string"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<{[key: string]: pulumi.Input<string>}> | undefined",
|
||||
"input": "pulumi.Input<{[key: string]: pulumi.Input<string>} | undefined> | undefined",
|
||||
"plain": "{[key: string]: string} | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
@ -549,7 +549,7 @@
|
|||
"plain": "interface{}"
|
||||
},
|
||||
"nodejs": {
|
||||
"input": "pulumi.Input<outputs.ObjectArgs | any[]> | undefined",
|
||||
"input": "pulumi.Input<outputs.ObjectArgs | any[] | undefined> | undefined",
|
||||
"plain": "outputs.Object | any[] | undefined"
|
||||
},
|
||||
"python": {
|
||||
|
|
|
@ -39,6 +39,14 @@ func Identifier(id string) TypeAst {
|
|||
return &idType{id}
|
||||
}
|
||||
|
||||
// IsIdentifier returns true if the AST node is an identifier.
|
||||
func IsIdentifier(t TypeAst) (string, bool) {
|
||||
if i, ok := t.(*idType); ok {
|
||||
return i.id, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Builds a `T[]` type from a `T` type.
|
||||
func Array(t TypeAst) TypeAst {
|
||||
return &arrayType{t}
|
||||
|
|
|
@ -277,16 +277,38 @@ func tokenToFunctionName(tok string) string {
|
|||
func (mod *modContext) typeAst(t schema.Type, input bool, constValue interface{}) tstypes.TypeAst {
|
||||
switch t := t.(type) {
|
||||
case *schema.OptionalType:
|
||||
// Treat optional(input(T)) as optional(input(optional(T))).
|
||||
elementType := t.ElementType
|
||||
if input, isInput := elementType.(*schema.InputType); isInput {
|
||||
elementType = &schema.InputType{
|
||||
ElementType: &schema.OptionalType{
|
||||
ElementType: input.ElementType,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return tstypes.Union(
|
||||
mod.typeAst(t.ElementType, input, constValue),
|
||||
mod.typeAst(elementType, input, constValue),
|
||||
tstypes.Identifier("undefined"),
|
||||
)
|
||||
case *schema.InputType:
|
||||
typ := mod.typeString(codegen.SimplifyInputUnion(t.ElementType), input, constValue)
|
||||
if typ == "any" {
|
||||
return tstypes.Identifier("any")
|
||||
elementType := t.ElementType
|
||||
optional, isOptional := elementType.(*schema.OptionalType)
|
||||
if isOptional {
|
||||
elementType = optional.ElementType
|
||||
}
|
||||
return tstypes.Identifier(fmt.Sprintf("pulumi.Input<%s>", typ))
|
||||
|
||||
typ := mod.typeAst(codegen.SimplifyInputUnion(elementType), input, constValue)
|
||||
if id, ok := tstypes.IsIdentifier(typ); ok && id == "any" {
|
||||
return typ
|
||||
}
|
||||
|
||||
if isOptional {
|
||||
typ = tstypes.Union(typ, tstypes.Identifier("undefined"))
|
||||
}
|
||||
|
||||
typeArgument := tstypes.TypeLiteral(tstypes.Normalize(typ))
|
||||
return tstypes.Identifier(fmt.Sprintf("pulumi.Input<%s>", typeArgument))
|
||||
case *schema.EnumType:
|
||||
return tstypes.Identifier(mod.objectType(nil, nil, t.Token, input, false, true))
|
||||
case *schema.ArrayType:
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
import * as assert from "assert";
|
||||
import { ComponentResource, CustomResource, DependencyResource, Inputs, Output, Resource, ResourceOptions, runtime,
|
||||
secret } from "../../index";
|
||||
import { ComponentResource, CustomResource, DependencyResource, Input, Inputs, Output, Resource, ResourceOptions,
|
||||
output, runtime, secret } from "../../index";
|
||||
import { asyncTest } from "../util";
|
||||
|
||||
const gstruct = require("google-protobuf/google/protobuf/struct_pb.js");
|
||||
|
@ -114,7 +114,9 @@ type TestBoolEnum = (typeof TestBoolEnum)[keyof typeof TestBoolEnum];
|
|||
interface TestInputs {
|
||||
aNum: number;
|
||||
bStr: string;
|
||||
bStrInput: Input<string>;
|
||||
cUnd: undefined;
|
||||
cUndInput: Input<undefined>;
|
||||
dArr: Promise<Array<any>>;
|
||||
id: string;
|
||||
urn: string;
|
||||
|
@ -207,16 +209,18 @@ describe("runtime", () => {
|
|||
|
||||
it("marshals basic properties correctly", asyncTest(async () => {
|
||||
const inputs: TestInputs = {
|
||||
"aNum": 42,
|
||||
"bStr": "a string",
|
||||
"cUnd": undefined,
|
||||
"dArr": Promise.resolve([ "x", 42, Promise.resolve(true), Promise.resolve(undefined) ]),
|
||||
"id": "foo",
|
||||
"urn": "bar",
|
||||
"strEnum": TestStrEnum.Foo,
|
||||
"intEnum": TestIntEnum.One,
|
||||
"numEnum": TestNumEnum.One,
|
||||
"boolEnum": TestBoolEnum.One,
|
||||
aNum: 42,
|
||||
bStr: "a string",
|
||||
bStrInput: output("a string"),
|
||||
cUnd: undefined,
|
||||
cUndInput: output(undefined),
|
||||
dArr: Promise.resolve([ "x", 42, Promise.resolve(true), Promise.resolve(undefined) ]),
|
||||
id: "foo",
|
||||
urn: "bar",
|
||||
strEnum: TestStrEnum.Foo,
|
||||
intEnum: TestIntEnum.One,
|
||||
numEnum: TestNumEnum.One,
|
||||
boolEnum: TestBoolEnum.One,
|
||||
};
|
||||
// Serialize and then deserialize all the properties, checking that they round-trip as expected.
|
||||
const transfer = gstruct.Struct.fromJavaScript(
|
||||
|
@ -224,7 +228,9 @@ describe("runtime", () => {
|
|||
const result = runtime.deserializeProperties(transfer);
|
||||
assert.strictEqual(result.aNum, 42);
|
||||
assert.strictEqual(result.bStr, "a string");
|
||||
assert.strictEqual(result.bStrInput, "a string");
|
||||
assert.strictEqual(result.cUnd, undefined);
|
||||
assert.strictEqual(result.cUndInput, undefined);
|
||||
assert.deepStrictEqual(result.dArr, [ "x", 42, true, null ]);
|
||||
assert.strictEqual(result.id, "foo");
|
||||
assert.strictEqual(result.urn, "bar");
|
||||
|
|
Loading…
Reference in a new issue