dsherret / ts-morph

TypeScript Compiler API wrapper for static analysis and programmatic code changes.
https://ts-morph.com
MIT License
4.97k stars 195 forks source link

Question: How to determine if a tuple element is optional #1553

Open GeekyEggo opened 3 months ago

GeekyEggo commented 3 months ago

I'm traversing an object type, and I've hit a bit of a road-bump whilst attempting to determine if a tuple's element type is optional.

For example, with a declaration like this:

type Color = "Red" | "Green" | "Blue";

export type Box = {
  colors: [Color, Color?];
};

How can I identify the 2nd element type of [Color, Color?] is optional?

My current attempts have predominantly been focused on the Type<ts.TupleType>, the tuple's underlying type.compilerType, and the tuple elements from type.getTupleElements(), however, I've been unsuccessful.

Any help in finding the information would be greatly appreciated, and thank you for such a fantastic library. 🙏

simonlovesyou commented 3 months ago

I couldn't find a way either using only ts-morph and had to read into the underlyingcompilerType to achieve it:

function checkOptionalTupleElements(type: Type<ts.Type>) {
  const stringifiedTupleIndexes = type.getTupleElements().map((_, index) => `${index}`)

  const optionalIndexed = type.compilerType
    .getProperties()
    // `getProperties` will return properties such as `length`, we need remove properties that are not an tuple element index.
    .filter((property) => stringifiedTupleIndexes.includes(property.escapedName as string))
    .map((typeSymbol) => (typeSymbol.getFlags() & SymbolFlags.Optional) !== 0)

  return optionalIndexed
}

// Create a new project
const project = new Project({ useInMemoryFileSystem: true })

const sourceFile = project.createSourceFile(
  "test.ts",
  `
    type Tuple = [number, number?];
  `
)

const typeAlias = sourceFile.getTypeAliasOrThrow("Tuple")
const type = typeAlias.getType()

const result = checkOptionalTupleElements(type)

console.log(result) // Output: [false, true]

It's not ideal, but may work for you?