Open rozzzly opened 8 years ago
Okay, so I'm trying to find a type definition for the schema/deserialized content of a package.json file.
Are you referring to the json schema for package.json
? That's probably in schemastore.org.
Or are you looking for the typings of immutable
? which you can install by typings install immutable
@unional I'm pretty sure he's after a type definition for package.json
.
We can add one to the registry, I've done something similar with other type definitions (like JSON schema). I know I would like a definition for package.json
and bower.json
, etc.
You can do a type definition for a json file? That I did not know! How does that get used? I mean json is basically a JavaScript object literal which can easily be typed. But how would that definition be applied to a JSON file?
@blakeembrey yes that is what I meant.
@johnnyreilly
how would that definition be applied to a JSON file?
To put it simply, just parse it into a plain old js object. Moreover, we can use an interface
to describe an object, so by extension, a json schema can also be modeled with little difficulty.
Imagine we read package.json
via readFile()
from node
's fs
module.
a string containing content of entire file ⮕ JSON.parse()
⮕ any
...wait, what?! that's not very useful. I'm lazy, I love autocompletion. And I love being able to use inline documentation to answer simple questions without having to do the following: switch to chrome. open new tab, google for somepackage
's docs, choose the for the official docs, then ctrl+f to search relevant section of the docs docs.
With a proper definition, I get autocomplete for the schema which makes development quicker, and documentation which lets me find solutions easier. ...and I just realized I made the argument for having typing themselves! If it's something us developers interface with programmatically, we should have a type definition for it so we can interface with said data structure in the best way possible.
So the idea is to do something like
export interface npmPackageSchema {
/** The name of the package. **/
name: string;
/** Optionally disallow npm from indexing this package**/
private?: boolean;
/** A list of the packages this package depends on. **/
dependencies?: {
/** A depended-upon package and its version (semver, filepath, etc) **/
[pkgName: string]: string;
};
/**
* Ensure that any "nonstandard" properties can
* still be accessed without making a fuss.
**/
[NonStandardProperty: string]: any;
};
const inspectPackage = (): npmPackageSchema => {
// Some read file operations...
// You can assume the variable `content` is a string
// with the contents of `package.json`.
return JSON.parse(content);
// The type of the return value is `any`. It which undergoes implicit type
// assertion (aka a cast) to the return type of the function, npmPackageSchema.
});
Then anything that uses the result of that function would get access to properties defined on that schema.
Nice @rozzzly :+1:
Because many different platforms, build targets, tools, plugins, or what-have-you use package.json
as a centralized location for storing configuration data, one should not be surprised that their package.json
file contains fields not described by the official schema. This shouldn't be too much of an issue thanks to type intersections.
export interface npmPackageSchemaPlugin_ava {
/**
* Configuration options for `ava`
**/
ava: {
/** Use the `tap` reporter? **/
tap?: boolean;
/** Number of worker processes used to run your tests. **/
concurrency?: number;
/** An array of glob expressions to use when searching for tests. **/
files?: string[];
};
}
const merged: npmPackageSchema & npmPackageSchemaPlugin_ava = inspectPackage() as any;
It would also be possible to define the the merged interface by creating a new interface which extends the base schema and the additions. fun fact: an interface can't implement anything but can extend multiple other interfaces and even classes! A class by comparison can implement any multiple interfaces, but can only extend one class.
export interface foo {
bar?: boolean;
}
export interface bar {
foo?: string;
}
export interface MySchema extends npmPackageSchema, foo, bar {
// would get kinda ugly if you have many schema mixed in,
// ones with long identifiers moreover,
// to have this just empty looks weird to me...
}
Perhaps the best solution could be:
export type MySchema = npmPackageSchema & foo & bar;
// alternate way to format that...
export type MySchema = npmPackageSchema
& npmPackageSchemaPlugin_foo
& npmPackageSchemaPlugin_bar;
// personally I prefer this
export type MySchema = ((npmPackageSchema)
& npmPackageSchemaPlugin_foo
& npmPackageSchemaPlugin_bar
);
I'm thinking of module augmentation in that case:
// official
declare module 'npm' {
interface packageJson {
...
}
}
// ava
declare module 'npm' {
interface packageJson {
// ava specific configuration
}
}
Maybe put this under common/npm
?
Ahhh even better, much more palatable. I only started using typescript a few months ago, haven't really used module
in any of the typings I've written; sticking to the es6 import
/export
syntax.
It might be better to keep this sort of thing global? It's tricky, but I wouldn't want to take the npm
name in case someone actually wants to write the module for it (most likely). Using globals, though, you can just rely on general interface merging without module augmentation also.
declare interface PackageJson {
main?: string
}
declare interface PackageJson {
...
}
However, we could also provide npm
's PackageJson
interface as an actual export for the NPM typings if someone wants to start them.
And @blakeembrey, I agree about the name. It would be presumptuous to just randomly publish this with the name: npm
. My thinking is:
PackageJson
as the name of that interface.PackageJson
as the tentative name for this typing (ie: in .typings.json
)ava
example; create another documented interface declaration with the name PackageJson
npm/npm
] repo (unless there is a better place to bring this up?)
PackageJson
interface would ideally be published as a part of a typing named npm
; hence, why I italicised the word "tentative" above. I cant think of anything off the top of my head. but I'm sure npm has some other things that could benefit from typedefs. Apparently their programmatic API isn't meant for consumption...npm
team would want to be the curator/maintainer, fine by me! I just want to make this a thing. This would give them an easy opportunity to get "official" typings with little/no effort.typings
registry as PackageJson
[ ] For that issue on [npm/npm
] include a .gif
of PackageJson
intellisense in vscode
Awesome gif!
Would this help? https://github.com/bcherny/json-schema-to-typescript
If we load an unknown package.json dynamically (not part of the build) it would be nice to have a pessimistic structure of how the JSON should look after parsing, something like this:
https://stackoverflow.com/questions/51794585/is-there-a-basic-ts-type-for-package-json
Okay, so I'm trying to find a type definition for the schema/deserialized content of a
package.json
file. You know the manifest as it were for annpm
package, exists at the root of our projects, contains stuff like:...but I can't find one. It's been like 45+ minutes and even though I'm a seasoned internets lurker, I still can't find it! I'm positive this must exist somewhere, its too common not to. But it's buried somewhere in hundreds of thousands of results referring to publishing
npm
packages, resolving type definitions, etc.So far I've tried dozens search queries with google, github via
org: typings _______
/org: DefinitelyTyped _______
, and of course via the clitypings search _______
.I still can't find it. I know one of you out there has to have used it before, might you be kind enough to share a link?
Additionally, what can we do so other developers looking for the same thing have an easier time? From my point of view, this essentially means getting the desired
.d.ts
higher in Google search results. I've got a few thoughts on how this could be achieved, but want to hear from you first.