TypeScript interface not recognized when in a .d.ts file

Viewed 1064

We have a file containing an interface that is not recognized by tsc or by vscode.

src/sap-truck-roster/resolver/RosterResolver.ts:40:17 - error TS2304: Cannot find name 'Context'.

// src\shared\types\Context.d.ts
import { Roster } from '@sap-truck-roster/entity/Roster'
import { Account } from '@it-portal/entity/Account'

 interface Context {
  user: Account
  dataSources: {
    sapRosterApi: Roster
  }
}

Apparently we need to use the option typeRoots in tsconfig as suggested here. But for one reason or another the interface Context is still not recognized. What are we missing here?

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@environment": ["src/environment"],
      "@utils/*": ["src/utils/*"]
    },
    "typeRoots": ["./node_modules/@types", "./src/shared/types/**/*.d.ts"],
    "rootDir": "./src",
    "outDir": "./dist",
    "target": "es6",
  },
  "exclude": ["node_modules"],
  "include": ["./src/**/*.tsx", "./src/**/*.ts", "./src/**/*.d.ts"]
}

Using the interface:

import { Resolver, Arg, Query, Ctx, Field, ObjectType, createUnionType } from 'type-graphql'
import { Roster } from '@sap-truck-roster/entity/Roster'
import { plainToClass } from 'class-transformer'

@Resolver()
export class RosterResolver {
  @Query(() => RosterQueryResultUnion)
  async roster(
    @Ctx() ctx: Context,   // use Context without import
    @Arg('date', () => String) date: string
  ): Promise<typeof RosterQueryResultUnion> {
    const response = await ctx.dataSources.sapRosterApi.getRoster(date)

    if (response.returnCode === 'OK') {
      return plainToClass(RosterArray, {
        data: response.data,
      })
    }
    return plainToClass(ApiError, {
      code: response.returnCode,
      message: response.errorMessage,
    })
  }
}
3 Answers

Not putting an export prevents it from being discoverable by TS.

.d.ts files are meant to declare or augment namespaces/modules, while banning any other TS operation as they are pure declaration files.

They aren't meant to avoid usage of import/export.

If you want to declare an interface globally, you should do so by augmenting the global module

In your case it would be

declare global {
  interface Context {
    user: Account
    dataSources: {
      sapRosterApi: Roster
    }
  }
}

But I strongly advise against it, it could be a pain in the ass for you in the future

For you it's better to create a normal .ts file and export the interface, then import it somewhere else. If that still doesn't work, check out if tsconfig paths are configured correctly or switch to use relative import paths.

Messing with typeRoots options usually also disable @types/* packages automatic discovery and cause pretty undebuggable problems.

You only can use the type or interface without importing it if it's in a .d.ts file and when you are not importing any type from any module in that .d.ts file.

You can achieve this using the module declaration.

declare module SomeName {
    interface Context {
        user: Account
        dataSources: {
          sapRosterApi: Roster
        }
    }
}

Now you can directly write it like this.

const ctx: SomeName.Context = {} // without importing anything

Update tsconfig.json from

"typeRoots": ["./node_modules/@types", "./src/shared/types/**/*.d.ts"],

to

"typeRoots": ["./node_modules/@types", "./src/shared/types"],

This must work. Let me know if didn't.

Codesandbox: https://codesandbox.io/s/ecstatic-tdd-tb11c?file=/src/App.tsx

Related