-
Notifications
You must be signed in to change notification settings - Fork 991
Example typings for featureReduce #2983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,116 @@ | ||
| import { Feature, FeatureCollection, Geometry } from "geojson"; | ||
| import { | ||
| Feature, | ||
| FeatureCollection, | ||
| GeoJsonProperties, | ||
| Geometry, | ||
| Point, | ||
| } from "geojson"; | ||
| import { earthRadius } from "@turf/helpers"; | ||
| import { geomReduce } from "@turf/meta"; | ||
| import { geomReduce, featureEach } from "@turf/meta"; | ||
|
|
||
| // would be in @turf/meta | ||
|
|
||
| // with initial value specified, things are relatively straightforward | ||
| export function featureReduce<R, T extends Feature | FeatureCollection>( | ||
| geojson: T, | ||
| callback: ( | ||
| previousValue: R, | ||
| currentFeature: T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T, | ||
| featureIndex: number | ||
| ) => R, | ||
| initialValue: R | ||
| ): R; | ||
|
|
||
| // with no initial value specified, previousValue can sometimes be Feature<G,P> | ||
| // the return value may also be undefined if we get a FeatureCollection without a guaranteed first element | ||
| export function featureReduce<T extends Feature | FeatureCollection>( | ||
| geojson: T, | ||
| callback: ( | ||
| previousValue: T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T, | ||
| currentFeature: T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T, | ||
| featureIndex: number | ||
| ) => T extends FeatureCollection<infer G, infer P> ? Feature<G, P> : T | ||
| ): T extends Feature | ||
| ? T | ||
| : T extends { features: [Feature<infer G, infer P>] } | ||
| ? Feature<G, P> | ||
| : T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | undefined | ||
| : never; | ||
|
|
||
| export function featureReduce<R, T extends Feature | FeatureCollection>( | ||
| geojson: T, | ||
| callback: ( | ||
| previousValue: R | T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T, | ||
| currentFeature: T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T, | ||
| featureIndex: number | ||
| ) => R, | ||
| initialValue?: R | ||
| ): T extends Feature ? R : R | undefined { | ||
| var previousValue: R | T extends FeatureCollection<infer G, infer P> | ||
| ? Feature<G, P> | ||
| : T = initialValue as any; | ||
| featureEach(geojson, function (currentFeature, featureIndex) { | ||
| if (featureIndex === 0 && initialValue === undefined) | ||
| previousValue = currentFeature as any; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this is actually different from how Array.prototype.reduce works when you don't specify an initial value. Without an initial value, you need to set previousValue to the first feature, but then only iterate 1...n in the array. I think in order to know whether or not we were passed an initial value, we need to use |
||
| else | ||
| previousValue = callback( | ||
| previousValue, | ||
| currentFeature as any, | ||
| featureIndex | ||
| ) as any; | ||
| }); | ||
| return previousValue as any; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made a bunch of sloppy |
||
| } | ||
|
|
||
| const feature: Feature<Point> = { | ||
| type: "Feature", | ||
| geometry: { type: "Point", coordinates: [0, 0] }, | ||
| properties: {}, | ||
| }; | ||
|
|
||
| const featureCollection: FeatureCollection<Point> = { | ||
| type: "FeatureCollection", | ||
| features: [feature], | ||
| }; | ||
|
|
||
| const emptyFeatureCollection: FeatureCollection<Point> & { features: never[] } = | ||
| { | ||
| type: "FeatureCollection", | ||
| features: [], | ||
| }; | ||
|
|
||
| // a FeatureCollection where we know that there is at least one feature (somehow) | ||
| const populatedFeatureCollection: { | ||
| type: "FeatureCollection"; | ||
| features: [Feature<Point, GeoJsonProperties>]; | ||
| } = { | ||
| type: "FeatureCollection", | ||
| features: [feature], | ||
| }; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bit is a little unfortunate. You cannot omit the explicit type definition here and use |
||
|
|
||
| const r1 = featureReduce(feature, (_acc, f, _i) => f); | ||
| const r2 = featureReduce(feature, (acc, _f, _i) => acc + 1, 0); | ||
| const r3 = featureReduce(featureCollection, (acc, f, _i) => f); | ||
| const r4 = featureReduce(featureCollection, (acc, _f, _i) => acc + 1, 0); | ||
| const r5 = featureReduce(emptyFeatureCollection, (acc, f, _i) => f); | ||
| const r6 = featureReduce(emptyFeatureCollection, (acc, _f, _i) => acc + 1, 0); | ||
| const r7 = featureReduce(populatedFeatureCollection, (acc, f, _i) => f); | ||
| const r8 = featureReduce( | ||
| populatedFeatureCollection, | ||
| (acc, _f, _i) => acc + 1, | ||
| 0 | ||
| ); | ||
|
|
||
| /** | ||
| * Calculates the geodesic area in square meters of one or more polygons. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just pay attention to the two function typings, not the one with the actual implementation itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference from lib.es5.d.ts on how Array.prototype.reduce is typed. Note that you can either specify an initial value and deal in that type for the reduce callbacks, or you can omit it and you are forced to use the shape of whatever is in the array.