[TypeScript] Compilation fails with bind("volume") in Audio service
ryze312 opened this issue · comments
TypeScript fails to compile when using binding on volume
in Audio
service
const audio = await Service.import("audio");
const widget = Widget.Label({
label: audio.speaker.bind("volume").as((v) => v.toString())
});
src/windows/bar.ts:28:51 - error TS18046: 'v' is of type 'unknown'.
28 label: audio.speaker.bind("volume").as((v) => v.toString())
~
Found 1 error in src/windows/bar.ts:28
VSCode LSP seems to infer the type correctly
Other fields work just fine, e.g is_muted
const audio = await Service.import("audio");
const widget = Widget.Label({
label: audio.speaker.bind("is_muted").as((v) => `test: ${v}`)
});
I'm having trouble reproducing this in my setup. Could you specify which versions of ags and bun you're using, as well as the exact command you're using that prompts the typescript error?
I am using AGS 1.8.2 and just running tsc
, there is no Bun
Hmm. Still couldn't reproduce it with tsc (version 5.5.2). Is there something weird with your tsconfig.json? Also, what happens if you explicitly type v
as a number (i.e. (v: number) => v.toString()
)?
what happens if you explicitly type v as a number
error TS2345: Argument of type '(v: number) => string' is not assignable to parameter of type '(v: unknown) => string'.
Is there something weird with your tsconfig.json?
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleDetection": "force",
"outDir": "build/target",
"typeRoots": ["./types/*"],
"strict": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noImplicitOverride": true,
"noImplicitAny": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noPropertyAccessFromIndexSignature": true,
"removeComments": true,
// This is needed to prevent compile error on checking imports like gi://
"skipLibCheck": true
},
// Include types manually
"include": ["src/**/*", "types/**/*.d.ts"]
}
I have to include types manually because of #352
It looks like the other bindings are broken as well; the example of bind("is_muted").as((v) => 'test: ${v}')
just doesn't exercise the failure case since unknown
can be string interpolated just fine. If you use (v: boolean | null)...
instead, it errors in the same way as with volume
.
I'm inclined to think this is an issue with how TSC propagates/remembers types. For a minimal example, consider:
const i = audio.speaker.bind("is_muted");
const q: Binding<Stream, "is_muted", boolean | null> = i;
which breaks with a telling:
main.ts:50:5 - error TS2322: Type 'Binding<Stream, string, unknown>' is not assignable to type 'Binding<Stream, "is_muted", boolean | null>'.
Type 'string' is not assignable to type '"is_muted"'.
50 var q: Binding<Stream, "is_muted", boolean | null> = i;
Note how the middle parameter has lost the specificity of keyof Stream
. If, on the other hand, we explicitly constrain "is_muted", such as below:
const k: keyof Stream = "is_muted";
const i = audio.speaker.bind(k);
const q: Binding<Stream, "is_muted", boolean | null> = i;
it compiles just fine.
After further investigation into why other Service
s seem to be able to bind without issue, I've narrowed the culprit down to get stream(): Gvc.MixerStream | null;
in types/service/audio.d.ts
. The inclusion of that property yields the keyof Stream
-> string
translation that causes the observed compilation issues. Specifically, the | null
aspect (which is consistent given that the Audio
service works just fine with get control(): Gvc.MixerControl;
).
TLDR: seems like this is probably either an issue with tsc's type system, or an issue with your tsconfig.json
. I'm insufficiently familiar with tsc to judge one way or another. I'd recommend either living with a workaround or opening an issue on the tsc repo to see if someone there can debug further.
Perhaps the keyof
aspect is somewhat inconsistent in TypeScript, this might be a compiler bug. I'll see if I can come up with a minimal example to reproduce it and forward to TypeScript upstream.
Looks like replacing the Props constraint with BindableProps here just fixes it.
thebind
method of a Service takes one of its properties' name as a string, it can't take a Binding object
I am guessing your typescript version is out of date, there was another issue #332 where tsc failed
Can not reproduce. tsc -v
is 5.4.5
any reason you want to transpile with tsc instead of using a bundler like esbuild or bun?
I am guessing your typescript version is out of date
Can not reproduce. tsc -v is 5.4.5
I am running tsc 5.5.3
any reason you want to transpile with tsc instead of using a bundler like esbuild or bun?
I prefer using plain tsc