TypeScript
TypeScript copied to clipboard
Incorrect semantic highlighting
🔎 Search Terms
token mismatch, syntax highlighting
🕗 Version & Regression Information
I tested with latest 5.0, 5.1, and 5.2 and it happens with all of them.
⏯ Playground Link
No response
💻 Code
import { ElectronAPI } from "@electron-toolkit/preload";
declare global {
interface Window {
electron: ElectronAPI;
api: unknown;
}
}
🙁 Actual behavior
https://github.com/microsoft/TypeScript/assets/20448879/d6d675c9-0576-4572-b9d8-fbd31d17d124
I have this file in my project that does this and it looks like a sourcemap / token map mismatch / offset or something.
🙂 Expected behavior
The tokens should be mapping to their respective reflections like in this playground
Additional information about the issue
I can't reproduce this in another file it just keeps happening in this specific file in this specific project. I can reproduce it if I copy the project and install the dependencies, so if someone wants to investigate it I can add you to a repository with the code.
I didn't notice this before but this bug actually causes the file to not extend the Window interface. Window["api"] does not exist until I rename index.d.ts to something else (like globals.d.ts). This is my tsconfig.json for clarity:
{
"extends": "@electron-toolkit/tsconfig/tsconfig.json",
"include": [
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.svelte",
"src/preload/*.d.ts"
],
"compilerOptions": {
"verbatimModuleSyntax": true,
"useDefineForClassFields": true,
"strict": false,
"allowJs": true,
"checkJs": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"]
},
"references": [{ "path": "./tsconfig.node.json" }]
}
We'll definitely need a way to repro this. Strange.
I remembered what template I was using, and it's enough to reproduce it out of the box:
pnpm create @quick-start/electron app-test --template=svelte-ts
cd app-test
pnpm i
code . src/preload/index.d.ts
# wait for ts-server to be done and see weird stuff
Weird, it's wrong but differently-wrong on my machine
This is specific to semantic highlighting
For me it goes a little farther than semantic highlighting. Can you try to do window.api; in preload/index.ts? For me it errors until I rename index.d.ts to something else like real.d.ts
This seems to be because of the index.ts right next to the index.d.ts. If I hover over the ElectrornAPI in the import, it shows the info of contextBridge, which only exists in the index.ts file.
I have investigated this issue and the cause seems to be a problem where tsserver is attempting to retrieve the highlights for index.d.ts, but instead returns the semantic highlighting for index.ts. This issue goes away by adding "disableSourceOfProjectReferenceRedirect": true, to the tsconfig, so I will be request @sheetalkamat to take a look at this.
Here is the smallest repro I was able to get:
// app-test/src/index.d.ts
declare global {
interface Window {
electron: ElectronAPI
api: unknown
}
}
// app-test/src/index.ts
const api = {}
// app-test/tsconfig.json
{
"include": [
"src/*.d.ts"
],
"compilerOptions": {
},
"references": [{ "path": "./tsconfig.node.json" }]
}
// app-test/tsconfig.node.json
{
"include": ["src/**/*"],
"compilerOptions": {
"composite": true,
}
}
The incorrect highlighting happens in index.d.ts in the space between e g in declare global:
I also noticed that the same thing happens with completionInfo, definitionAndBoundSpan`, and possibly others. Here are example tsserver logs for all three I found:
Info 122 request:
{
"seq": 33,
"type": "request",
"command": "documentHighlights",
"arguments": {
"file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
"line": 1,
"offset": 9,
"filesToSearch": [
"c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts"
]
}
}
Info 124 response:
{"seq":0,
"type":"response",
"command":"documentHighlights",
"request_seq":33,
"success":true,
"body":[{"file":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
"highlightSpans":
[{"start":{"line":1,"offset":7},
"end":{"line":1,"offset":10},
"contextStart":{"line":1,"offset":1},
"contextEnd":{"line":1,"offset":15},
"kind":"writtenReference"
}]
}]
}
Info 125 request:
{
"seq": 34,
"type": "request",
"command": "completionInfo",
"arguments": {
"file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
"line": 1,
"offset": 9,
"triggerCharacter": {
"id": "type-tree",
"range": {
"start": {
"line": 0,
"character": 8
},
"end": {
"line": 0,
"character": 8
}
},
"maxDepth": 6
}
}
}
Info 132 response:
{
"seq":0,
"type":"response",
"command":"completionInfo",
"request_seq":34,"success":true,
"body":{"isGlobalCompletion":false,
"isMemberCompletion":false,
"isNewIdentifierLocation":false,
"entries":[],
"__tsExplorerResponse":
{
"id":"type-tree",
"typeInfo":
{
"kind":"object",
"properties":[],
"indexInfos":[],
"symbolMeta":
{
"name":"api",
"flags":2,
"declarations":
[{
"location":
{
"fileName":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
"range":{"start":{"line":0,"character":6},"end":{"line":0,"character":9}}
}
}]
},
"id":"85,14,0"
}
}
}
}
Info 139 request:
{
"seq": 37,
"type": "request",
"command": "definitionAndBoundSpan",
"arguments": {
"file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
"line": 1,
"offset": 8
}
}
Info 141 response:
{
"seq":0,
"type":"response",
"command":"definitionAndBoundSpan",
"request_seq":37,
"success":true,
"body":
{
"definitions":
[{
"file":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
"start":{"line":1,"offset":7},
"end":{"line":1,"offset":10},
"contextStart":{"line":1,"offset":1},
"contextEnd":{"line":1,"offset":15}
}],
"textSpan":{"start":{"line":1,"offset":7},"end":{"line":1,"offset":10}}
}
}
I will look into this issue but this is such a bad configuration. There may be many places some of the assumptions going wrong here.
app-test/src/index.d.ts is considered output of app-test/src/index.ts since its tsconfig has composite which means declaration to be true as well.