I can't see a way to do it from sf
because it seems to drop geometry type for empty geometries. But you can create a table with one row and then use SQL to delete all rows.
Example, here's a simple 1-row POINT spatial data frame:
> d1
Simple feature collection with 1 feature and 1 field
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 0.1055935 ymin: 0.4832159 xmax: 0.1055935 ymax: 0.4832159
CRS: NA
Z geometry
1 a POINT (0.1055935 0.4832159)
Write it to a geopackage:
> st_write(d1, "empty.gpkg", "empty")
writing GPKG: substituting LOCAL_CS["Undefined Cartesian SRS"] for missing CRS
Writing layer `empty' to data source `empty.gpkg' using driver `GPKG'
Writing 1 features with 1 fields and geometry type Point.
Using the RSQLite
package, make a connection:
> con = dbConnect(SQLite(), "empty.gpkg")
Delete every row:
> dbExecute(con, "delete from empty where 1 = 1")
[1] 5
And now when we read back it has zero rows:
> st_read("empty.gpkg")
Reading layer `empty' from data source
`/home/rowlings/Downloads/SO/empty/empty.gpkg' using driver `GPKG'
Simple feature collection with 0 features and 1 field
Bounding box: xmin: NA ymin: NA xmax: NA ymax: NA
Projected CRS: Undefined Cartesian SRS
And note sf
has no clue of the geometry, although it is in the geopackage metadata table as "POINT":
> dbReadTable(con, "gpkg_geometry_columns")
table_name column_name geometry_type_name srs_id z m
1 empty geom POINT 100000 0 0