mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
Map any parameters of interface method and call signatures as checked values (#2273)
This commit is contained in:
@@ -5297,10 +5297,12 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null
|
||||
// A parameter a TypeScript program types `any` takes whatever the
|
||||
// caller passes: the checked-dynamic slot, as an `any`-typed binding
|
||||
// already is (dynFallbackType). Declaration files keep their paths.
|
||||
// Only function declarations, spelled function types and lambda
|
||||
// parameters whose default is the only source of their type (`(n =
|
||||
// lookup() ?? 5) => ...` with an `any` lookup): other lambdas and
|
||||
// methods in object literals keep their existing checked-dynamic story.
|
||||
// Only function declarations, spelled function types, method and call
|
||||
// signatures of interfaces and type literals (`execute(params: any):
|
||||
// Promise<R>`), and lambda parameters whose default is the only source
|
||||
// of their type (`(n = lookup() ?? 5) => ...` with an `any` lookup):
|
||||
// other lambdas and methods in object literals keep their existing
|
||||
// checked-dynamic story.
|
||||
if (
|
||||
!pt &&
|
||||
!rest &&
|
||||
@@ -5309,6 +5311,8 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null
|
||||
decl.parent !== undefined &&
|
||||
(ts.isFunctionDeclaration(decl.parent) ||
|
||||
ts.isFunctionTypeNode(decl.parent) ||
|
||||
ts.isMethodSignatureDeclaration(decl.parent) ||
|
||||
ts.isCallSignatureDeclaration(decl.parent) ||
|
||||
((ts.isArrowFunction(decl.parent) || ts.isFunctionExpression(decl.parent)) &&
|
||||
decl.initializer !== undefined &&
|
||||
decl.type === undefined &&
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/method-signature-any-params.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// A method or call signature of an interface whose parameter is typed `any`
|
||||
// (directly, or through an alias that resolves to `any`) takes whatever the
|
||||
// caller passes, as a function type's `any` parameter already does: the
|
||||
// interface compiles, and implementations receive the checked-dynamic value.
|
||||
|
||||
type Loose = any;
|
||||
|
||||
interface Tool {
|
||||
name: string;
|
||||
execute(id: string, params: any, extra?: Loose): Promise<string>;
|
||||
describe(value: Loose): string;
|
||||
}
|
||||
|
||||
interface Formatter {
|
||||
(value: any): string;
|
||||
}
|
||||
|
||||
const tools: Tool[] = [
|
||||
{
|
||||
name: "count",
|
||||
execute: async (id, params) => `${id} has ${Object.keys(params ?? {}).length} keys`,
|
||||
describe: (value) => `count(${Array.isArray(value) ? "array" : typeof value})`,
|
||||
},
|
||||
];
|
||||
|
||||
const format: Formatter = (value) => (typeof value === "number" ? value.toFixed(1) : String(value));
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const inputs: unknown[] = [{ a: 1, b: [2, 3] }, "text", 42, null, [1, 2]];
|
||||
for (const tool of tools) {
|
||||
for (const input of inputs) {
|
||||
console.log(tool.name, await tool.execute("call", input), tool.describe(input));
|
||||
}
|
||||
console.log(tool.name, await tool.execute("extra", { k: true }, { more: "yes" }));
|
||||
}
|
||||
console.log(format(3), format("x"), format(undefined));
|
||||
}
|
||||
|
||||
main().catch((e: unknown) => console.log("failed", e instanceof Error ? e.message : String(e)));
|
||||
@@ -0,0 +1 @@
|
||||
{ "plain": 4000 }
|
||||
Reference in New Issue
Block a user