Skip to content

TS errors when consuming butterfloat with noUncheckedIndexedAccess compiler option enabled. #104

@achou11

Description

@achou11

I have a vite-based project that has the following tsconfig, which I consider to be pretty standard/reasonable for such apps:

{
	"compilerOptions": {
		"allowJs": true,
		"allowImportingTsExtensions": true,
		"erasableSyntaxOnly": true,
		"esModuleInterop": true,
		"incremental": true,
		"isolatedModules": true,
		"lib": ["es2022", "dom", "dom.iterable"],
		"module": "preserve",
		"moduleDetection": "force",
		"noEmit": true,
		"noImplicitOverride": true,
		"noUncheckedIndexedAccess": true,
		"resolveJsonModule": true,
		"skipLibCheck": true,
		"strict": true,
		"target": "es2022",
		"verbatimModuleSyntax": true,
		// Butterfloat-specific
		"jsx": "react",
		"jsxFactory": "jsx",
		"jsxFragmentFactory": "Fragment"
	},
	"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
	"exclude": ["node_modules", "dist"]
}

The only source code I have is this, which is extracted from the getting started page:

import { jsx, run } from 'butterfloat'

interface HelloProps {
  to: string
}

function Hello({ to }: HelloProps) {
  return <p className="hello">Hello {to}</p>
}

function Main() {
  return <Hello to="World" />
}

const container = document.getElementById('container')!
run(container, Main)

When running type checks i.e. tsc, I get the following errors:

node_modules/.pnpm/butterfloat@1.6.4/node_modules/butterfloat/static-dom.ts:28:36 - error TS2538: Type 'undefined' cannot be used as an index type.

28     let ns = context?.namespaceMap[nsAbbrev]
                                      ~~~~~~~~

node_modules/.pnpm/butterfloat@1.6.4/node_modules/butterfloat/static-dom.ts:43:34 - error TS2538: Type 'undefined' cannot be used as an index type.

43       ns = context?.namespaceMap[nsAbbrev]
                                    ~~~~~~~~

node_modules/.pnpm/butterfloat@1.6.4/node_modules/butterfloat/static-dom.ts:48:44 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
      Type 'undefined' is not assignable to type 'string'.

48     element = document.createElementNS(ns, elementName)
                                              ~~~~~~~~~~~

  node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts:10148:5
    10148     createElementNS(namespace: string | null, qualifiedName: string, options?: string | ElementCreationOptions): Element;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The last overload is declared here.

node_modules/.pnpm/butterfloat@1.6.4/node_modules/butterfloat/static-dom.ts:70:42 - error TS2538: Type 'undefined' cannot be used as an index type.

70       const ns = context?.namespaceMap?.[nsAbbrev]
                                            ~~~~~~~~

node_modules/.pnpm/butterfloat@1.6.4/node_modules/butterfloat/static-dom.ts:74:34 - error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  Type 'undefined' is not assignable to type 'string'.

74       element.setAttributeNS(ns, attributeName, (value ?? '').toString())
                                    ~~~~~~~~~~~~~

If I remove the noUncheckedIndexedAccess option from my tsconfig, the errors go away. The errors actually make sense to me, but I'm a little surprised that TS is even complaining about them in the first place, given it's code that lives in a dependency. I would think my excludes configuration and the usage of skipLibCheck would tell TS not to do that. However, from a brief investigation, using skipLibCheck won't necessarily disable typechecking deps code (docs). From what I gathered, the fact that it is complaining about code in a dep apparently suggests a potential misconfiguration of the dep, although I could be mistaken about that.

There's a chance that this isn't an issue with butterfloat but it's the first time I've come across something like this where a compiler option that ideally is only relevant to my source code is complaining about a dep, which is not ideal.


For extra context, here are the relevant parts of my package.json:

{
	"type": "module",
	"devEngines": {
		"packageManager": {
			"name": "pnpm",
			"version": "~10.18.3"
		},
		"runtime": {
			"name": "node",
			"version": "~22.20.0"
		}
	},
	"scripts": {
		"app:build": "vite build",
		"app:dev": "vite",
		"check:eslint": "eslint . --cache",
		"check:format": "prettier . --check --cache",
		"check:types": "tsc",
		"check": "pnpm run \"/^check:.*/\""
	},
	"dependencies": {
		"butterfloat": "1.6.4",
		"rxjs": "7.8.2"
	},
	"devDependencies": {
		"@eslint/compat": "1.4.0",
		"@eslint/js": "9.38.0",
		"@ianvs/prettier-plugin-sort-imports": "4.7.0",
		"@types/node": "22.18.11",
		"eslint": "9.38.0",
		"globals": "16.4.0",
		"lint-staged": "16.2.4",
		"prettier": "3.6.2",
		"typescript": "5.9.3",
		"typescript-eslint": "8.46.1",
		"vite": "7.1.10"
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions